explore
key systems
new
docs
discord
search scripts
⌘K
explore
key systems
new
docs
discord
sign in
⌘↵
--
publishes from anywhere on this page
new paste
untitled.luau
empty
/ 512kb
open file
⌘O
explore
key systems
new
docs
sign in
catnhub-open-source-copy.luau
8500 lines · 353kb
/ 512kb
open file
⌘O
-- https://discord.gg/TwqtNreVMr for updates local Vanta = (function(...) local Players = game:GetService("Players"); local TweenService = game:GetService("TweenService"); local UserInputService = game:GetService("UserInputService"); local HttpService = game:GetService("HttpService"); local RunService = game:GetService("RunService"); local Lighting = game:GetService("Lighting"); local CoreGui = game:GetService("CoreGui"); local plr = Players.LocalPlayer; local unpack = table.unpack or unpack; local Vanta = {Version="2.1"}; local U = {fast=false}; local function rgb(r, g, b) return Color3.fromRGB(r, g, b); end local THEMES = {Graphite={Background=rgb(9, 9, 11),Sidebar=rgb(12, 12, 14),Panel=rgb(22, 22, 26),Element=rgb(17, 17, 20),Hover=rgb(26, 26, 30),Stroke=rgb(36, 36, 42),Text=rgb(237, 237, 240),SubText=rgb(150, 150, 160),Muted=rgb(98, 98, 108)},Slate={Background=rgb(9, 11, 15),Sidebar=rgb(12, 14, 19),Panel=rgb(20, 24, 32),Element=rgb(16, 19, 26),Hover=rgb(24, 28, 38),Stroke=rgb(33, 39, 52),Text=rgb(232, 236, 244),SubText=rgb(140, 150, 170),Muted=rgb(92, 102, 122)},Warm={Background=rgb(12, 11, 10),Sidebar=rgb(15, 14, 13),Panel=rgb(26, 24, 22),Element=rgb(21, 19, 18),Hover=rgb(30, 28, 26),Stroke=rgb(42, 39, 36),Text=rgb(240, 236, 230),SubText=rgb(158, 150, 140),Muted=rgb(108, 101, 93)},Paper={Light=true,Background=rgb(250, 250, 250),Sidebar=rgb(244, 244, 245),Panel=rgb(255, 255, 255),Element=rgb(255, 255, 255),Hover=rgb(244, 244, 246),Stroke=rgb(228, 228, 231),Text=rgb(24, 24, 27),SubText=rgb(100, 100, 110),Muted=rgb(160, 160, 170)}}; THEMES.Halloween = {Limited={From={10,15},To={11,3},Ends="Nov 3"},Accent={rgb(255, 122, 24),rgb(30, 12, 0)},Background=rgb(10, 7, 14),Sidebar=rgb(14, 10, 19),Panel=rgb(27, 19, 35),Element=rgb(20, 14, 27),Hover=rgb(33, 23, 42),Stroke=rgb(50, 36, 60),Text=rgb(246, 238, 230),SubText=rgb(172, 156, 170),Muted=rgb(116, 100, 120)}; local THEME_ORDER = {"Graphite","Slate","Warm","Paper","Halloween"}; local function themeActive(name) local t = THEMES[name]; if not t then return false; end if not t.Limited then return true; end local ok, d = pcall(os.date, "*t"); if (not ok or (type(d) ~= "table")) then return false; end local today = (d.month * 100) + d.day; local a, b = (t.Limited.From[1] * 100) + t.Limited.From[2], (t.Limited.To[1] * 100) + t.Limited.To[2]; if (a <= b) then return (today >= a) and (today <= b); end return (today >= a) or (today <= b); end local function themeList() local list = {}; for _, n in ipairs(THEME_ORDER) do if themeActive(n) then table.insert(list, n); end end return list; end local ACCENTS = {Mono={rgb(237, 237, 240),rgb(14, 14, 16),Light={rgb(24, 24, 27),rgb(250, 250, 250)}},Blue={rgb(59, 130, 246),rgb(255, 255, 255)},Emerald={rgb(16, 185, 129),rgb(3, 20, 13)},Amber={rgb(245, 158, 11),rgb(32, 18, 0)},Rose={rgb(244, 63, 94),rgb(255, 255, 255)},Violet={rgb(139, 92, 246),rgb(255, 255, 255)},Orange={rgb(249, 115, 22),rgb(32, 14, 0)}}; local ACCENT_ORDER = {"Mono","Blue","Emerald","Amber","Rose","Violet","Orange"}; Vanta.Themes, Vanta.Accents = THEMES, ACCENTS; Vanta.ThemeActive, Vanta.ThemeList = themeActive, themeList; local STATUS = {Good=rgb(52, 199, 123),Warn=rgb(245, 166, 35),Bad=rgb(240, 82, 82)}; U.assets = {Glow="rbxassetid://8992230677"}; local BUILDER = "rbxasset://fonts/families/BuilderSans.json"; local F = {Regular=Font.new(BUILDER, Enum.FontWeight.Regular),Medium=Font.new(BUILDER, Enum.FontWeight.Medium),SemiBold=Font.new(BUILDER, Enum.FontWeight.SemiBold),Mono=Font.new("rbxasset://fonts/families/RobotoMono.json", Enum.FontWeight.Medium)}; F.Bold = F.SemiBold; F.Display = F.SemiBold; local function new(class, props, children) local obj = Instance.new(class); local parent; if obj:IsA("GuiObject") then obj.BorderSizePixel = 0; end for k, v in pairs(props or {}) do if (k == "Parent") then parent = v; else obj[k] = v; end end for _, c in ipairs(children or {}) do c.Parent = obj; end if parent then obj.Parent = parent; end return obj; end local function corner(r) return new("UICorner", {CornerRadius=UDim.new(0, r or 6)}); end local function stroke(color, thickness, transparency) return new("UIStroke", {Color=(color or rgb(36, 36, 42)),Thickness=(thickness or 1),Transparency=(transparency or 0),ApplyStrokeMode=Enum.ApplyStrokeMode.Border}); end local function pad(l, r, t, b) return new("UIPadding", {PaddingLeft=UDim.new(0, l or 0),PaddingRight=UDim.new(0, r or l or 0),PaddingTop=UDim.new(0, t or l or 0),PaddingBottom=UDim.new(0, b or t or l or 0)}); end local function list(padding, dir, align, valign) return new("UIListLayout", {Padding=UDim.new(0, padding or 0),FillDirection=(dir or Enum.FillDirection.Vertical),HorizontalAlignment=(align or Enum.HorizontalAlignment.Left),VerticalAlignment=(valign or Enum.VerticalAlignment.Top),SortOrder=Enum.SortOrder.LayoutOrder}); end local function text(props) return new("TextLabel", {BackgroundTransparency=1,FontFace=(props.FontFace or F.Regular),TextColor3=(props.TextColor3 or rgb(237, 237, 240)),TextSize=(props.TextSize or 13),TextXAlignment=(props.TextXAlignment or Enum.TextXAlignment.Left),TextYAlignment=(props.TextYAlignment or Enum.TextYAlignment.Center),Text=(props.Text or ""),RichText=(props.RichText or false),TextWrapped=(props.TextWrapped or false),TextTruncate=(props.TextTruncate or Enum.TextTruncate.None),Size=(props.Size or UDim2.new(1, 0, 0, 16)),Position=(props.Position or UDim2.new()),AnchorPoint=(props.AnchorPoint or Vector2.new()),AutomaticSize=(props.AutomaticSize or Enum.AutomaticSize.None),LayoutOrder=(props.LayoutOrder or 0),ZIndex=(props.ZIndex or 1),Parent=props.Parent}); end local function tween(obj, time, goal, style, dir) local t = TweenService:Create(obj, TweenInfo.new((U.fast and 0) or time, style or Enum.EasingStyle.Quint, dir or Enum.EasingDirection.Out), goal); t:Play(); return t; end local function guiParent() if (type(gethui) == "function") then local ok, h = pcall(gethui); if (ok and h) then return h; end end local ok = pcall(function() return CoreGui.Name; end); if ok then return CoreGui; end return plr:WaitForChild("PlayerGui"); end local function screenGui(name, order) local g = new("ScreenGui", {Name=name,ResetOnSpawn=false,ZIndexBehavior=Enum.ZIndexBehavior.Sibling,DisplayOrder=(order or 100),IgnoreGuiInset=true}); if ((type(syn) == "table") and (type(syn.protect_gui) == "function")) then pcall(syn.protect_gui, g); end g.Parent = guiParent(); return g; end local function keyName(key) if (typeof(key) ~= "EnumItem") then return "None"; end local names = {LeftControl="LCtrl",RightControl="RCtrl",LeftShift="LShift",RightShift="RShift",LeftAlt="LAlt",RightAlt="RAlt",Return="Enter",MouseButton1="M1",MouseButton2="M2",MouseButton3="M3",Backquote="`"}; return names[key.Name] or key.Name; end local function round(v, step) step = step or 1; local r = math.floor((v / step) + 0.5) * step; local decimals = tostring(step):match("%.(%d+)"); if decimals then r = tonumber(string.format("%." .. #decimals .. "f", r)); end return r; end local function fmt(v) if (math.floor(v) == v) then return tostring(math.floor(v)); end return tostring(v); end local function toHex(c) return string.format("%02X%02X%02X", math.floor((c.R * 255) + 0.5), math.floor((c.G * 255) + 0.5), math.floor((c.B * 255) + 0.5)); end local function fromHex(h) h = tostring(h or ""):gsub("#", ""); if (#h ~= 6) then return nil; end local r, g, b = tonumber(h:sub(1, 2), 16), tonumber(h:sub(3, 4), 16), tonumber(h:sub(5, 6), 16); if not (r and g and b) then return nil; end return Color3.fromRGB(r, g, b); end local function luma(c) return (c.R * 0.299) + (c.G * 0.587) + (c.B * 0.114); end local function safeCall(fn, ...) if (type(fn) ~= "function") then return; end local args = {...}; task.spawn(function() local ok, err = pcall(fn, unpack(args)); if not ok then warn("[vanta] callback error: " .. tostring(err)); end end); end local function draggable(handle, target, conns, onStart) local dragging, start, origin; table.insert(conns, handle.InputBegan:Connect(function(input) if ((input.UserInputType == Enum.UserInputType.MouseButton1) or (input.UserInputType == Enum.UserInputType.Touch)) then dragging, start, origin = true, input.Position, target.Position; if onStart then onStart(); end local c; c = input.Changed:Connect(function() if (input.UserInputState == Enum.UserInputState.End) then dragging = false; c:Disconnect(); end end); end end)); table.insert(conns, UserInputService.InputChanged:Connect(function(input) if not dragging then return; end if ((input.UserInputType == Enum.UserInputType.MouseMovement) or (input.UserInputType == Enum.UserInputType.Touch)) then local d = input.Position - start; target.Position = UDim2.new(origin.X.Scale, origin.X.Offset + d.X, origin.Y.Scale, origin.Y.Offset + d.Y); end end)); end local fs = {ok=((type(writefile) == "function") and (type(readfile) == "function"))}; fs.read = function(path) if not fs.ok then return nil; end local ok, res = pcall(function() if ((type(isfile) == "function") and not isfile(path)) then return nil; end return readfile(path); end); return (ok and res) or nil; end; fs.write = function(path, data) if not fs.ok then return; end pcall(function() local built = ""; for part in path:gmatch("([^/]+)/") do built = ((built == "") and part) or (built .. "/" .. part); if ((type(makefolder) == "function") and ((type(isfolder) ~= "function") or not isfolder(built))) then makefolder(built); end end writefile(path, data); end); end; local fontTried = false; U.loadFonts = function() if fontTried then return; end fontTried = true; if (not fs.ok or (type(getcustomasset) ~= "function") or (type(isfile) ~= "function")) then return; end local done, fam = false, nil; task.spawn(function() local ok, res = pcall(function() local base = "https://cdn.jsdelivr.net/gh/rsms/inter@v3.19/docs/font-files/Inter-"; local faces = {}; for _, w in ipairs({{"Regular",400},{"Medium",500},{"SemiBold",600}}) do local file = "Vanta/Inter-" .. w[1] .. ".otf"; if not isfile(file) then fs.write(file, game:HttpGet(base .. w[1] .. ".otf")); end table.insert(faces, {name=w[1],weight=w[2],style="normal",assetId=getcustomasset(file)}); end fs.write("Vanta/Inter.json", HttpService:JSONEncode({name="Inter",faces=faces})); return getcustomasset("Vanta/Inter.json"); end); if ok then fam = res; end done = true; end); local waited = 0; while not done and (waited < 4) do task.wait(0.05); waited = waited + 0.05; end if (type(fam) == "string") then F.Regular = Font.new(fam, Enum.FontWeight.Regular); F.Medium = Font.new(fam, Enum.FontWeight.Medium); F.SemiBold = Font.new(fam, Enum.FontWeight.SemiBold); F.Bold, F.Display = F.SemiBold, F.SemiBold; end end; Vanta.MissingIcons = {}; local ICONS = {bell="rbxassetid://97392696311902",bot="rbxassetid://80451686744860",bug="rbxassetid://83626408925438",cat="rbxassetid://124252153404931",["chart-column"]="rbxassetid://97915995538580",check="rbxassetid://93898873302694",["chevron-down"]="rbxassetid://134243273101015",["circle-check"]="rbxassetid://85262178816537",["circle-x"]="rbxassetid://76821953846248",clock="rbxassetid://121808839832144",coins="rbxassetid://116510979641930",crosshair="rbxassetid://134242818164054",droplet="rbxassetid://100597455015098",egg="rbxassetid://117851493400222",ellipsis="rbxassetid://140019550645825",eye="rbxassetid://100033680381365",["eye-off"]="rbxassetid://135928786788378",fish="rbxassetid://124360663785796",["gamepad-2"]="rbxassetid://92483947987410",ghost="rbxassetid://113822048130017",gift="rbxassetid://109855212076373",hash="rbxassetid://82890331678520",house="rbxassetid://98755624629571",info="rbxassetid://124560466474914",layers="rbxassetid://81973586053257",["layout-dashboard"]="rbxassetid://139929981863901",["layout-grid"]="rbxassetid://81344910161871",list="rbxassetid://113179976918783",["map-pin"]="rbxassetid://84279202219901",["message-circle"]="rbxassetid://127255077587058",minus="rbxassetid://118026365011536",monitor="rbxassetid://72664649203050",["mouse-pointer-2"]="rbxassetid://117093892862228",music="rbxassetid://113343203848535",["panel-left"]="rbxassetid://97419752870313",power="rbxassetid://96479131758775",["refresh-cw"]="rbxassetid://138133190015277",search="rbxassetid://121018724060431",server="rbxassetid://92188766517878",settings="rbxassetid://80758916183665",shield="rbxassetid://110987169760162",["shield-check"]="rbxassetid://87354736164608",shuffle="rbxassetid://132382786975101",siren="rbxassetid://134210267818039",["sliders-horizontal"]="rbxassetid://85538382643347",["sun-moon"]="rbxassetid://75752898854559",swords="rbxassetid://81872698913435",table="rbxassetid://109109148250737",tag="rbxassetid://129104970103940",target="rbxassetid://87563802520297",timer="rbxassetid://85473888890506",["trending-up"]="rbxassetid://81819858538839",["triangle-alert"]="rbxassetid://125920361880643",trophy="rbxassetid://131545003268773",users="rbxassetid://115398113982385",wheat="rbxassetid://85261952080359",wrench="rbxassetid://112148279212860",x="rbxassetid://110786993356448",zap="rbxassetid://130551565616516"}; local ICON_ALIAS = {home="house",close="x",cross="x",gear="settings",cog="settings",warning="triangle-alert",alert="triangle-alert",error="circle-x",success="circle-check",sword="swords",chart="chart-column",cursor="mouse-pointer-2",combat="swords",visuals="eye",misc="ellipsis",players="users",teleport="map-pin",farm="wheat",auto="bot"}; U.setIcon = function(img, name) if (not name or (name == "")) then img.Image = ""; return; end name = tostring(name); if name:find("^rbxassetid://") then img.Image = name; return; end local id = ICONS[name] or ICONS[ICON_ALIAS[name] or ""]; if not id then Vanta.MissingIcons[name] = true; end img.Image = id or ""; end; local blurFx, blurRefs = nil, 0; U.blur = function(on, size) if on then blurRefs = blurRefs + 1; if (not blurFx or not blurFx.Parent) then blurFx = new("BlurEffect", {Name="VantaBlur",Size=0,Parent=Lighting}); end tween(blurFx, 0.4, {Size=(size or 12)}); else blurRefs = math.max(blurRefs - 1, 0); if (blurFx and (blurRefs == 0)) then local b = blurFx; tween(b, 0.3, {Size=0}).Completed:Connect(function() if ((blurRefs == 0) and b.Parent) then b:Destroy(); if (blurFx == b) then blurFx = nil; end end end); end end end; local function buildTokens(themeName, accentName, customColor) local base = THEMES[themeName] or THEMES.Graphite; local T = {}; for k, v in pairs(base) do T[k] = v; end T.Good, T.Warn, T.Bad = STATUS.Good, STATUS.Warn, STATUS.Bad; local a = ACCENTS[accentName]; if a then local pick = (base.Light and a.Light) or a; if (base.Accent and (accentName == "Mono")) then pick = base.Accent; end T.Accent, T.OnAccent = pick[1], pick[2]; else T.Accent = customColor or ACCENTS.Mono[1]; T.OnAccent = ((luma(T.Accent) > 0.6) and rgb(14, 14, 16)) or rgb(255, 255, 255); end T.Accent2 = T.Accent; return T; end U.defaultT = buildTokens("Graphite", "Mono"); local notifyGui, notifyHolder; local NOTIFY = {Info={"info","SubText"},Success={"circle-check","Good"},Warning={"triangle-alert","Warn"},Error={"circle-x","Bad"}}; U.notify = function(win, opts) opts = opts or {}; local T = (win and win.T) or U.defaultT; if (not notifyGui or not notifyGui.Parent) then notifyGui = screenGui("VantaNotify", 200); notifyHolder = new("Frame", {BackgroundTransparency=1,AnchorPoint=Vector2.new(1, 1),Position=UDim2.new(1, -16, 1, -16),Size=UDim2.new(0, 300, 1, -32),Parent=notifyGui}, {new("UIListLayout", {Padding=UDim.new(0, 8),VerticalAlignment=Enum.VerticalAlignment.Bottom,HorizontalAlignment=Enum.HorizontalAlignment.Right,SortOrder=Enum.SortOrder.LayoutOrder})}); end local kind = NOTIFY[opts.Type or "Info"] or NOTIFY.Info; local color = T[kind[2]] or T.SubText; local duration = opts.Duration or 4; local slot = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,Parent=notifyHolder}); local card = new("CanvasGroup", {BackgroundColor3=T.Panel,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,Position=UDim2.new(0, 24, 0, 0),GroupTransparency=1,Parent=slot}, {corner(8),stroke(T.Stroke, 1, 0)}); local inner = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,Parent=card}, {pad(12, 12, 11, 13)}); local ic = new("ImageLabel", {BackgroundTransparency=1,ImageColor3=color,Position=UDim2.fromOffset(0, 1),Size=UDim2.fromOffset(16, 16),Parent=inner}); U.setIcon(ic, opts.Icon or kind[1]); local body = new("Frame", {BackgroundTransparency=1,Position=UDim2.fromOffset(26, 0),Size=UDim2.new(1, -46, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,Parent=inner}, {list(2)}); text({Text=(opts.Title or "Notice"),FontFace=F.SemiBold,TextSize=13,TextColor3=T.Text,LayoutOrder=1,Parent=body,Size=UDim2.new(1, 0, 0, 18),TextTruncate=Enum.TextTruncate.AtEnd}); if (opts.Content and (opts.Content ~= "")) then text({Text=opts.Content,TextColor3=T.SubText,TextSize=12,TextWrapped=true,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,LayoutOrder=2,Parent=body}); end local bar = new("Frame", {BackgroundColor3=color,BackgroundTransparency=0.5,BorderSizePixel=0,AnchorPoint=Vector2.new(0, 1),Position=UDim2.new(0, 0, 1, 0),Size=UDim2.new(1, 0, 0, 2),Parent=card}); local close = new("TextButton", {Text="",BackgroundTransparency=1,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -6, 0, 6),Size=UDim2.fromOffset(22, 22),ZIndex=3,Parent=card}); local cx = new("ImageLabel", {BackgroundTransparency=1,ImageColor3=T.Muted,AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.fromScale(0.5, 0.5),Size=UDim2.fromOffset(12, 12),Parent=close}); U.setIcon(cx, "x"); local gone = false; local function dismiss() if gone then return; end gone = true; tween(card, 0.25, {Position=UDim2.new(0, 24, 0, 0),GroupTransparency=1}); task.delay(0.3, function() slot:Destroy(); end); end close.MouseButton1Click:Connect(dismiss); close.MouseEnter:Connect(function() tween(cx, 0.12, {ImageColor3=T.Text}); end); close.MouseLeave:Connect(function() tween(cx, 0.15, {ImageColor3=T.Muted}); end); tween(card, 0.3, {Position=UDim2.new(0, 0, 0, 0),GroupTransparency=0}); tween(bar, duration, {Size=UDim2.new(0, 0, 0, 2)}, Enum.EasingStyle.Linear); task.delay(duration, dismiss); local items = {}; for _, c in ipairs(notifyHolder:GetChildren()) do if c:IsA("Frame") then table.insert(items, c); end end if (#items > 5) then items[1]:Destroy(); end end; local Window = {}; Window.__index = Window; local Tab = {}; Tab.__index = Tab; local Section = {}; Section.__index = Section; local SIDE_OPEN, SIDE_CLOSED, TOP_H = 184, 52, 46; Vanta.Notify = function(selfOrVanta, opts) local win = ((selfOrVanta ~= Vanta) and (getmetatable(selfOrVanta) == Window) and selfOrVanta) or nil; U.notify(win, opts); end; Window.Notify = function(self, opts) U.notify(self, opts); end; Window.bind = function(self, obj, prop, token) obj[prop] = self.T[token]; table.insert(self.Bound, {obj=obj,prop=prop,token=token}); return obj; end; local function bstroke(win, parent, token, thickness, transparency) local s = stroke(win.T[token], thickness, transparency); s.Parent = parent; win:bind(s, "Color", token); return s; end Window.icon = function(self, parent, name, size, color, props) props = props or {}; local img = new("ImageLabel", {BackgroundTransparency=1,AnchorPoint=(props.AnchorPoint or Vector2.new(0.5, 0.5)),Position=(props.Position or UDim2.fromScale(0.5, 0.5)),Size=UDim2.fromOffset(size, size),ZIndex=(props.ZIndex or 1),Parent=parent}); if (type(color) == "string") then self:bind(img, "ImageColor3", color); else img.ImageColor3 = color or self.T.Text; end U.setIcon(img, name); return img; end; Window._rebuildTokens = function(self) local fresh = buildTokens(self.ThemeName, self.AccentName, self.CustomAccent); for k in pairs(self.T) do self.T[k] = nil; end for k, v in pairs(fresh) do self.T[k] = v; end end; Window._apply = function(self, animate) for i = #self.Bound, 1, -1 do local b = self.Bound[i]; if not b.obj.Parent then table.remove(self.Bound, i); elseif animate then tween(b.obj, 0.25, {[b.prop]=self.T[b.token]}); else b.obj[b.prop] = self.T[b.token]; end end for _, fn in ipairs(self.Redraws) do pcall(fn); end end; Window.SetTheme = function(self, name) if not themeActive(name) then return; end self.ThemeName = name; self.ThemeChosen = true; self:_rebuildTokens(); self:_apply(true); self:_fxSync(); self:_save(); end; Window._fxStop = function(self) local fx = self.Fx; if not fx then return; end self.Fx = nil; fx.alive = false; for _, o in ipairs(fx.objs) do pcall(function() o:Destroy(); end); end if (self.BrandMark and self.BrandMark.Parent) then self.BrandMark.Visible = true; end end; Window._fxStart = function(self) if (self.Fx or self.Destroyed or not self.Body) then return; end local fx = {alive=true,objs={}}; self.Fx = fx; local function keep(o) table.insert(fx.objs, o); return o; end local linear = Enum.EasingStyle.Linear; local rng = Random.new(); if self.BrandTile then local ghost = keep(self:icon(self.BrandTile, "ghost", 15, "Accent")); if self.BrandMark then self.BrandMark.Visible = false; end TweenService:Create(ghost, TweenInfo.new(1.5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, -1, true), {Position=UDim2.new(0.5, 0, 0.5, -2)}):Play(); end local glint = keep(new("Frame", {Name="Glint",BackgroundColor3=Color3.new(1, 1, 1),Size=UDim2.new(1, 0, 0, 2),ZIndex=40,Parent=self.Body})); local grad = new("UIGradient", {Color=ColorSequence.new(Color3.fromRGB(255, 122, 24), Color3.fromRGB(160, 100, 230)),Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0, 1),NumberSequenceKeypoint.new(0.5, 0),NumberSequenceKeypoint.new(1, 1)}),Offset=Vector2.new(-1, 0),Parent=glint}); TweenService:Create(grad, TweenInfo.new(3.2, linear, Enum.EasingDirection.Out, -1, false, 1.2), {Offset=Vector2.new(1, 0)}):Play(); local holder = keep(new("Frame", {Name="Embers",BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),ZIndex=35,Parent=self.Body})); local colors = {Color3.fromRGB(255, 140, 40),Color3.fromRGB(255, 108, 20),Color3.fromRGB(165, 105, 235)}; for _ = 1, 24 do task.spawn(function() task.wait(rng:NextNumber(0, 8)); while fx.alive and holder.Parent do if (U.fast or not self.Open) then task.wait(0.5); else local size = rng:NextInteger(2, 4); local x = rng:NextNumber(0.03, 0.97); local life = rng:NextNumber(6, 11); local dot = new("Frame", {BackgroundColor3=colors[rng:NextInteger(1, #colors)],BackgroundTransparency=1,AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.new(x, 0, 1, 8),Size=UDim2.fromOffset(size, size),Parent=holder}, {corner(size)}); TweenService:Create(dot, TweenInfo.new(life, linear), {Position=UDim2.new(x + rng:NextNumber(-0.06, 0.06), 0, 0, -8)}):Play(); TweenService:Create(dot, TweenInfo.new(life * 0.25, Enum.EasingStyle.Sine, Enum.EasingDirection.Out), {BackgroundTransparency=0.4}):Play(); task.delay(life * 0.55, function() if dot.Parent then TweenService:Create(dot, TweenInfo.new(life * 0.45, Enum.EasingStyle.Sine, Enum.EasingDirection.In), {BackgroundTransparency=1}):Play(); end end); task.wait(life); dot:Destroy(); end end end); end end; Window._fxSync = function(self) if (self.ThemeName == "Halloween") then self:_fxStart(); else self:_fxStop(); end end; local DOCK = 38; Window._dockBuild = function(self, opts) self.DockOn = opts.Dock ~= false; U.dockSlots = U.dockSlots or {}; local slot = 1; while U.dockSlots[slot] do slot = slot + 1; end U.dockSlots[slot] = self; self.DockSlot = slot; local function viewport() local cam = workspace.CurrentCamera; return (cam and cam.ViewportSize) or Vector2.new(1280, 720); end local function clamp(px, py) local v = viewport(); return math.clamp(px, 4, math.max((v.X - DOCK) - 4, 4)), math.clamp(py, 4, math.max((v.Y - DOCK) - 4, 4)); end local x, y = 14, math.floor(viewport().Y * 0.34) + ((slot - 1) * (DOCK + 8)); local saved = self.Saved.__dock; if ((type(saved) == "table") and tonumber(saved.x) and tonumber(saved.y)) then x, y = saved.x, saved.y; end x, y = clamp(x, y); local btn = new("TextButton", {Name="Dock",Text="",AutoButtonColor=false,BackgroundTransparency=1,Position=UDim2.fromOffset(x, y),Size=UDim2.fromOffset(DOCK, DOCK),Visible=false,ZIndex=10,Parent=self.Gui}); local scale = new("UIScale", {Scale=0.85,Parent=btn}); local face = new("CanvasGroup", {BackgroundColor3=self.T.Panel,Size=UDim2.fromScale(1, 1),GroupTransparency=1,Parent=btn}, {corner(10)}); self:bind(face, "BackgroundColor3", "Panel"); if opts.Icon then self:icon(face, opts.Icon, 18, "Text"); else local letter = text({Text=string.upper(self.Title:sub(1, 1)),FontFace=F.SemiBold,TextSize=14,TextXAlignment=Enum.TextXAlignment.Center,Size=UDim2.fromScale(1, 1),Parent=face}); self:bind(letter, "TextColor3", "Text"); end local ring = new("Frame", {BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),ZIndex=3,Parent=btn}, {corner(10)}); local ringStroke = bstroke(self, ring, "Stroke", 1, 1); local dot = new("Frame", {Name="Badge",AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, 3, 0, -3),Size=UDim2.fromOffset(9, 9),BackgroundTransparency=1,ZIndex=5,Parent=btn}, {corner(5)}); self:bind(dot, "BackgroundColor3", "Good"); local dotRing = bstroke(self, dot, "Panel", 2, 1); self.Dock = {btn=btn,scale=scale,face=face,stroke=ringStroke,dot=dot,dotRing=dotRing,shown=false}; btn.MouseEnter:Connect(function() if not self.Dock.shown then return; end tween(face, 0.12, {BackgroundColor3=self.T.Hover}); tween(ringStroke, 0.12, {Color=self.T.Accent}); end); btn.MouseLeave:Connect(function() tween(face, 0.15, {BackgroundColor3=self.T.Panel}); tween(ringStroke, 0.15, {Color=self.T.Stroke}); end); local dragging, moved, startPos, origin; local function onBegin(input) if ((input.UserInputType ~= Enum.UserInputType.MouseButton1) and (input.UserInputType ~= Enum.UserInputType.Touch)) then return; end dragging, moved, startPos, origin = true, false, input.Position, btn.Position; local c; c = input.Changed:Connect(function() if (input.UserInputState ~= Enum.UserInputState.End) then return; end c:Disconnect(); dragging = false; if moved then self.DockPos = {x=btn.Position.X.Offset,y=btn.Position.Y.Offset}; self:_save(); else self:SetOpen(true); end end); end local function onMove(input) if not dragging then return; end if ((input.UserInputType ~= Enum.UserInputType.MouseMovement) and (input.UserInputType ~= Enum.UserInputType.Touch)) then return; end local d = input.Position - startPos; if (not moved and (d.Magnitude < 5)) then return; end moved = true; local nx, ny = clamp(origin.X.Offset + d.X, origin.Y.Offset + d.Y); btn.Position = UDim2.fromOffset(nx, ny); end btn.InputBegan:Connect(onBegin); table.insert(self.Conns, UserInputService.InputChanged:Connect(onMove)); self.Dock.onBegin, self.Dock.onMove = onBegin, onMove; self:_dockSync(); end; local TOP_CLEAR, EDGE = 64, 12; Window._screen = function(self) local cam = workspace.CurrentCamera; local vp = (cam and cam.ViewportSize) or Vector2.new(1280, 720); local s = self:_scale(); return vp, self.Root.Size.X.Offset * s, self.Root.Size.Y.Offset * s; end; Window._clampCentre = function(self, cx, cy) local vp, w, h = self:_screen(); cx = math.clamp(cx, (w / 2) + EDGE, math.max((w / 2) + EDGE, (vp.X - (w / 2)) - EDGE)); cy = math.clamp(cy, (h / 2) + TOP_CLEAR, math.max((h / 2) + TOP_CLEAR, (vp.Y - (h / 2)) - EDGE)); return cx, cy; end; Window._moveCentre = function(self, cx, cy) local vp = self:_screen(); cx, cy = self:_clampCentre(cx, cy); local was = self.Dragged; self.Dragged = false; self.Root.Position = UDim2.new(0.5, math.floor((cx - (vp.X / 2)) + 0.5), 0.5, math.floor((cy - (vp.Y / 2)) + 0.5)); self.Dragged = was; end; Window._place = function(self) local vp, w, h = self:_screen(); local saved = self.Saved.__pos; if ((type(saved) == "table") and tonumber(saved.x) and tonumber(saved.y)) then self.PosSaved = {x=tonumber(saved.x),y=tonumber(saved.y)}; self:_moveCentre((vp.X / 2) + saved.x, (vp.Y / 2) + saved.y); return; end local others = {}; for _, o in ipairs(U.windows or {}) do if ((o ~= self) and not o.Destroyed and o.Open and o.Root and o.Root.Visible) then table.insert(others, {c=(o.Root.AbsolutePosition + (o.Root.AbsoluteSize / 2)),size=o.Root.AbsoluteSize}); end end local function free(x, y) for _, r in ipairs(others) do if ((math.abs(x - r.c.X) < (((w + r.size.X) / 2) + 8)) and (math.abs(y - r.c.Y) < (((h + r.size.Y) / 2) + 8))) then return false; end end return true; end local spots = {{(vp.X / 2),(vp.Y / 2)}}; for _, r in ipairs(others) do table.insert(spots, {(r.c.X + ((r.size.X + w) / 2) + 16),r.c.Y}); table.insert(spots, {((r.c.X - ((r.size.X + w) / 2)) - 16),r.c.Y}); table.insert(spots, {r.c.X,(r.c.Y + ((r.size.Y + h) / 2) + 16)}); end for _, spot in ipairs(spots) do local x, y = self:_clampCentre(spot[1], spot[2]); if free(x, y) then self:_moveCentre(x, y); return; end end local last = others[#others]; self:_moveCentre(last.c.X + 36, last.c.Y + 36); end; Window._keepOnScreen = function(self) local c = self.Root.AbsolutePosition + (self.Root.AbsoluteSize / 2); self:_moveCentre(c.X, c.Y); end; Window.ResetPosition = function(self) self.PosSaved, self.Saved.__pos = nil, nil; self:_place(); self:_save(); end; Window.SetBadge = function(self, on) local d = self.Dock; if not d then return; end on = on == true; d.badge = on; tween(d.dot, 0.2, {BackgroundTransparency=((on and 0) or 1)}); tween(d.dotRing, 0.2, {Transparency=((on and 0) or 1)}); end; Window._dockSync = function(self) local d = self.Dock; if not d then return; end local show = (self.DockOn == true) and not self.Open and not self.Destroyed; if (show == d.shown) then return; end d.shown = show; if show then d.btn.Visible = true; tween(d.scale, 0.25, {Scale=1}); tween(d.face, 0.2, {GroupTransparency=0}); tween(d.stroke, 0.2, {Transparency=0}); else tween(d.scale, 0.15, {Scale=0.85}); tween(d.face, 0.15, {GroupTransparency=1}); tween(d.stroke, 0.15, {Transparency=1}); task.delay(0.18, function() if (not d.shown and d.btn.Parent) then d.btn.Visible = false; end end); end end; Window.SetAccent = function(self, a) if ((type(a) == "string") and ACCENTS[a]) then self.AccentName, self.CustomAccent = a, nil; elseif (typeof(a) == "Color3") then self.AccentName, self.CustomAccent = nil, a; else return; end self:_rebuildTokens(); self:_apply(true); self:_save(); end; Window.SetKey = function(self, key) if ((typeof(key) == "EnumItem") and (key.EnumType == Enum.KeyCode)) then self.Key = key; self:_save(); end end; Window.SetScale = function(self, v) self.UserScale = math.clamp(tonumber(v) or 1, 0.6, 1.5); if self.Open then tween(self.Scale, 0.25, {Scale=self:_scale()}); end self:_save(); end; Window._scale = function(self) return (self.BaseScale or 1) * (self.UserScale or 1); end; Window._flush = function(self) if not self.ConfigPath then return; end local out = {}; for k, v in pairs(self.Saved) do out[k] = v; end for flag, f in pairs(self.Flags) do local ok, v = pcall(f.Save); if (ok and (v ~= nil)) then out[flag] = v; end end out.__accent = self.AccentName; if self.ThemeChosen then out.__theme = self.ThemeName; end if self.DockPos then out.__dock = self.DockPos; end if self.PosSaved then out.__pos = self.PosSaved; end out.__key, out.__scale, out.__blur = self.Key and self.Key.Name, self.UserScale, self.BlurPref; local ok, json = pcall(HttpService.JSONEncode, HttpService, out); if ok then fs.write(self.ConfigPath, json); end end; Window._save = function(self) if (not self.ConfigPath or self.Loading) then return; end self.SaveQueued = true; if self.SaveRunning then return; end self.SaveRunning = true; task.delay(0.8, function() self.SaveRunning = false; if (not self.SaveQueued or self.Destroyed) then return; end self.SaveQueued = false; self:_flush(); end); end; Window._flag = function(self, flag, get, set, save, load) if not flag then return nil; end self.Flags[flag] = {Get=get,Set=set,Save=(save or get)}; local saved = self.Saved[flag]; if (saved ~= nil) then local ok, v = pcall(load or function(x) return x; end, saved); if (ok and (v ~= nil)) then return v; end end return nil; end; Window._index = function(self, tab, name, desc, row, sec) if (not name or (name == "")) then return; end table.insert(self.Index, {name=tostring(name),desc=tostring(desc or ""),tab=tab,row=row,sec=sec}); end; Window._flash = function(self, row) if not row.Parent then return; end local prevColor = row.BackgroundColor3; row.BackgroundColor3 = self.T.Accent; tween(row, 0.1, {BackgroundTransparency=0.82}); task.delay(0.9, function() if not row.Parent then return; end tween(row, 0.5, {BackgroundTransparency=1}).Completed:Connect(function() if row.Parent then row.BackgroundColor3 = self.T.Hover; end end); end); end; Vanta.Window = function(self, opts) opts = opts or {}; plr = Players.LocalPlayer or plr; while not plr do task.wait(); plr = Players.LocalPlayer; end U.loadFonts(); local self = setmetatable({}, Window); self.Title = opts.Title or "Vanta"; self.Subtitle = opts.Subtitle or ""; self.Key = ((typeof(opts.Key) == "EnumItem") and (opts.Key.EnumType == Enum.KeyCode) and opts.Key) or Enum.KeyCode.RightControl; self.OnDestroy = opts.OnDestroy; self.Tabs, self.Flags, self.Conns, self.Bound = {}, {}, {}, {}; self.Redraws, self.Index, self.Binds, self.SideLabels = {}, {}, {}, {}; self.Toggles = {}; U.windows = U.windows or {}; table.insert(U.windows, self); self.Open, self.Destroyed, self.OrderCount = true, false, 0; self.UserScale, self.BlurPref = 1, opts.Blur == true; self.SideCollapsed = false; self.ThemeName = (themeActive(opts.Theme) and opts.Theme) or "Graphite"; self.AccentName = (ACCENTS[opts.Accent] and opts.Accent) or "Mono"; self.ConfigPath = (opts.Config and (tostring(opts.Config) .. "/settings.json")) or nil; self.Saved = {}; if self.ConfigPath then local raw = fs.read(self.ConfigPath); if raw then local ok, data = pcall(HttpService.JSONDecode, HttpService, raw); if (ok and (type(data) == "table")) then self.Saved = data; end end local s = self.Saved; if ((type(s.__theme) == "string") and themeActive(s.__theme)) then self.ThemeName = s.__theme; end self.ThemeChosen = (type(s.__theme) == "string") and (s.__theme == self.ThemeName); if ((type(s.__accent) == "string") and ACCENTS[s.__accent]) then self.AccentName = s.__accent; end if (type(s.__key) == "string") then local ok, k = pcall(function() return Enum.KeyCode[s.__key]; end); if (ok and k) then self.Key = k; end end if (type(s.__scale) == "number") then self.UserScale = math.clamp(s.__scale, 0.6, 1.5); end if (type(s.__blur) == "boolean") then self.BlurPref = s.__blur; end end self.T = {}; self:_rebuildTokens(); local T = self.T; local size = opts.Size or UDim2.fromOffset(660, 440); local gui = screenGui("Vanta_" .. HttpService:GenerateGUID(false):sub(1, 8), 150); self.Gui = gui; local root = new("Frame", {Name="Window",BackgroundTransparency=1,AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.fromScale(0.5, 0.5),Size=size,Parent=gui}); self.Root = root; self.Scale = new("UIScale", {Scale=1,Parent=root}); local function fit() local cam = workspace.CurrentCamera; if not cam then return; end local vp = cam.ViewportSize; local w, h = self.Root.Size.X.Offset, self.Root.Size.Y.Offset; self.BaseScale = math.max(math.min(1, (vp.X - 24) / w, (vp.Y - 24) / h), 0.45); if (self.Open and self.Booted) then self.Scale.Scale = self:_scale(); task.defer(function() if not self.Destroyed then self:_keepOnScreen(); end end); end end if workspace.CurrentCamera then table.insert(self.Conns, workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(fit)); end self.Shadow = new("ImageLabel", {Name="Shadow",BackgroundTransparency=1,Image=U.assets.Glow,ImageColor3=Color3.new(0, 0, 0),ImageTransparency=0.7,AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.new(0.5, 0, 0.5, 14),Size=UDim2.new(1, 120, 1, 120),ZIndex=0,Parent=root}); local body = new("CanvasGroup", {Name="Body",BackgroundColor3=T.Background,Size=UDim2.fromScale(1, 1),GroupTransparency=1,Parent=root}, {corner(10)}); self:bind(body, "BackgroundColor3", "Background"); self.Body = body; local border = new("Frame", {Name="Border",BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),ZIndex=30,Parent=root}, {corner(10)}); bstroke(self, border, "Stroke", 1, 0); self.Border = border; local sidebar = new("Frame", {Name="Sidebar",BackgroundColor3=T.Sidebar,Size=UDim2.new(0, SIDE_OPEN, 1, 0),ClipsDescendants=true,ZIndex=2,Parent=body}); self:bind(sidebar, "BackgroundColor3", "Sidebar"); self.Sidebar = sidebar; local sideLine = new("Frame", {BorderSizePixel=0,AnchorPoint=Vector2.new(1, 0),Position=UDim2.fromScale(1, 0),Size=UDim2.new(0, 1, 1, 0),Parent=sidebar}); self:bind(sideLine, "BackgroundColor3", "Stroke"); local brand = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 58),Parent=sidebar}); local tile = new("Frame", {BackgroundColor3=T.Element,Position=UDim2.fromOffset(14, 16),Size=UDim2.fromOffset(26, 26),Parent=brand}, {corner(7)}); self:bind(tile, "BackgroundColor3", "Hover"); bstroke(self, tile, "Stroke", 1, 0); self.BrandTile = tile; if opts.Icon then self.BrandMark = self:icon(tile, opts.Icon, 14, "Text"); else local letter = text({Text=string.upper(self.Title:sub(1, 1)),FontFace=F.SemiBold,TextSize=13,TextXAlignment=Enum.TextXAlignment.Center,Size=UDim2.fromScale(1, 1),Parent=tile}); self:bind(letter, "TextColor3", "Text"); self.BrandMark = letter; end local titleLbl = text({Text=self.Title,FontFace=F.SemiBold,TextSize=13,Position=UDim2.fromOffset(50, 13),Size=UDim2.new(1, -60, 0, 16),TextTruncate=Enum.TextTruncate.AtEnd,Parent=brand}); self:bind(titleLbl, "TextColor3", "Text"); local subLbl = text({Text=self.Subtitle,TextSize=11,Position=UDim2.fromOffset(50, 29),Size=UDim2.new(1, -60, 0, 14),TextTruncate=Enum.TextTruncate.AtEnd,Parent=brand}); self:bind(subLbl, "TextColor3", "Muted"); table.insert(self.SideLabels, titleLbl); table.insert(self.SideLabels, subLbl); local tabScroll = new("ScrollingFrame", {Name="Tabs",BackgroundTransparency=1,BorderSizePixel=0,Position=UDim2.fromOffset(0, 58),Size=UDim2.new(1, 0, 1, -110),CanvasSize=UDim2.new(),AutomaticCanvasSize=Enum.AutomaticSize.Y,ScrollBarThickness=0,Parent=sidebar}); self.TabScroll = tabScroll; self.Pill = new("Frame", {BackgroundColor3=T.Hover,Position=UDim2.fromOffset(8, 0),Size=UDim2.new(1, -16, 0, 32),Visible=false,ZIndex=1,Parent=tabScroll}, {corner(6)}); self:bind(self.Pill, "BackgroundColor3", "Hover"); self.TabInner = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,Parent=tabScroll}, {list(2),pad(8, 8, 2, 8)}); table.insert(self.Conns, self.TabInner:GetPropertyChangedSignal("AbsoluteSize"):Connect(function() if (self.Current and self.Booted) then self:_movePill(self.Current, true); end end)); local profile = new("Frame", {BackgroundTransparency=1,AnchorPoint=Vector2.new(0, 1),Position=UDim2.fromScale(0, 1),Size=UDim2.new(1, 0, 0, 52),Parent=sidebar}); local pline = new("Frame", {BorderSizePixel=0,Size=UDim2.new(1, 0, 0, 1),Parent=profile}); self:bind(pline, "BackgroundColor3", "Stroke"); local avatar = new("ImageLabel", {BackgroundColor3=T.Hover,Position=UDim2.fromOffset(14, 14),Size=UDim2.fromOffset(24, 24),Parent=profile}, {corner(12)}); self:bind(avatar, "BackgroundColor3", "Hover"); local nameLbl = text({Text=plr.DisplayName,FontFace=F.Medium,TextSize=12,Position=UDim2.fromOffset(46, 10),Size=UDim2.new(1, -54, 0, 16),TextTruncate=Enum.TextTruncate.AtEnd,Parent=profile}); self:bind(nameLbl, "TextColor3", "Text"); self.StatLbl = text({Text="",TextSize=11,Position=UDim2.fromOffset(46, 26),Size=UDim2.new(1, -54, 0, 14),TextTruncate=Enum.TextTruncate.AtEnd,Parent=profile}); self:bind(self.StatLbl, "TextColor3", "Muted"); table.insert(self.SideLabels, nameLbl); table.insert(self.SideLabels, self.StatLbl); task.spawn(function() local ok, img = pcall(Players.GetUserThumbnailAsync, Players, plr.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size100x100); if (ok and avatar.Parent) then avatar.Image = img; end end); local content = new("Frame", {Name="Content",BackgroundTransparency=1,Position=UDim2.fromOffset(SIDE_OPEN, 0),Size=UDim2.new(1, -SIDE_OPEN, 1, 0),Parent=body}); self.Content = content; local topbar = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, TOP_H),ZIndex=5,Parent=content}); self.Topbar = topbar; local function iconButton(iconName, props, onClick, danger) local b = new("TextButton", {Text="",BackgroundTransparency=1,Size=UDim2.fromOffset(28, 28),ZIndex=6,Parent=topbar}); for k, v in pairs(props) do b[k] = v; end local bg = new("Frame", {BackgroundColor3=((danger and T.Bad) or T.Hover),BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),Parent=b}, {corner(6)}); if not danger then self:bind(bg, "BackgroundColor3", "Hover"); end local ic = self:icon(b, iconName, 15, "SubText"); b.MouseEnter:Connect(function() tween(bg, 0.1, {BackgroundTransparency=((danger and 0.8) or 0)}); tween(ic, 0.1, {ImageColor3=((danger and self.T.Bad) or self.T.Text)}); end); b.MouseLeave:Connect(function() tween(bg, 0.15, {BackgroundTransparency=1}); tween(ic, 0.15, {ImageColor3=self.T.SubText}); end); b.MouseButton1Click:Connect(onClick); return b, ic; end local _, collapseIcon = iconButton("panel-left", {Position=UDim2.fromOffset(10, 9)}, function() self:SetSidebar(not self.SideCollapsed); end); self.CollapseIcon = collapseIcon; self.Crumb = text({Text="",RichText=true,FontFace=F.Medium,TextSize=13,Position=UDim2.fromOffset(48, 0),Size=UDim2.new(1, -230, 1, 0),TextTruncate=Enum.TextTruncate.AtEnd,Parent=topbar}); self:bind(self.Crumb, "TextColor3", "Text"); iconButton("x", {AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -10, 0, 9)}, function() self:SetOpen(false); local how = (self.DockOn and ("Hidden. Click the icon or press " .. keyName(self.Key) .. " to bring it back.")) or ("Hidden. Press " .. keyName(self.Key) .. " to bring it back."); Vanta.Notify(self, {Title=self.Title,Content=how,Icon="eye-off"}); end, true); iconButton("minus", {AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -42, 0, 9)}, function() self:SetOpen(false); end); iconButton("sun-moon", {AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -74, 0, 9)}, function() local list = themeList(); local i = table.find(list, self.ThemeName) or 1; self:SetTheme(list[(i % #list) + 1]); end); local searchWrap = new("Frame", {BackgroundColor3=T.Hover,BackgroundTransparency=1,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -106, 0, 9),Size=UDim2.fromOffset(28, 28),ClipsDescendants=true,ZIndex=6,Parent=topbar}, {corner(6)}); self:bind(searchWrap, "BackgroundColor3", "Hover"); self.SearchWrap = searchWrap; self.SearchStroke = bstroke(self, searchWrap, "Stroke", 1, 1); self.SearchIcon = self:icon(searchWrap, "search", 15, "SubText", {AnchorPoint=Vector2.new(0, 0.5),Position=UDim2.new(0, 6, 0.5, 0)}); self.SearchBox = new("TextBox", {Text="",PlaceholderText="Search settings",FontFace=F.Regular,TextSize=12,TextColor3=T.Text,PlaceholderColor3=T.Muted,TextXAlignment=Enum.TextXAlignment.Left,BackgroundTransparency=1,ClearTextOnFocus=false,Visible=false,Position=UDim2.fromOffset(28, 0),Size=UDim2.new(1, -34, 1, 0),Parent=searchWrap}); self:bind(self.SearchBox, "TextColor3", "Text"); self:bind(self.SearchBox, "PlaceholderColor3", "Muted"); local topLine = new("Frame", {BorderSizePixel=0,Position=UDim2.fromOffset(0, TOP_H),Size=UDim2.new(1, 0, 0, 1),Parent=content}); self:bind(topLine, "BackgroundColor3", "Stroke"); self.Pages = new("Frame", {Name="Pages",BackgroundTransparency=1,Position=UDim2.fromOffset(0, TOP_H + 1),Size=UDim2.new(1, 0, 1, -(TOP_H + 1)),ClipsDescendants=true,Parent=content}); self:_buildSearch(); local grip = new("TextButton", {Text="",BackgroundTransparency=1,AnchorPoint=Vector2.new(1, 1),Position=UDim2.fromScale(1, 1),Size=UDim2.fromOffset(18, 18),ZIndex=40,Parent=root}); for i = 0, 1 do local dot = new("Frame", {BorderSizePixel=0,AnchorPoint=Vector2.new(1, 1),Position=UDim2.new(1, -4 - (i * 4), 1, -4 + (i * 0)),Size=UDim2.fromOffset(2, 2),Parent=grip}, {corner(1)}); self:bind(dot, "BackgroundColor3", "Muted"); end local rz, rzStart, rzSize; grip.InputBegan:Connect(function(input) if ((input.UserInputType == Enum.UserInputType.MouseButton1) or (input.UserInputType == Enum.UserInputType.Touch)) then rz, rzStart, rzSize = true, input.Position, root.AbsoluteSize / math.max(self.Scale.Scale, 0.01); local c; c = input.Changed:Connect(function() if (input.UserInputState == Enum.UserInputState.End) then rz = false; c:Disconnect(); end end); end end); table.insert(self.Conns, UserInputService.InputChanged:Connect(function(input) if not rz then return; end if ((input.UserInputType == Enum.UserInputType.MouseMovement) or (input.UserInputType == Enum.UserInputType.Touch)) then local d = (input.Position - rzStart) / math.max(self.Scale.Scale, 0.01); root.Size = UDim2.fromOffset(math.clamp(rzSize.X + d.X, 540, 1100), math.clamp(rzSize.Y + d.Y, 360, 760)); end end)); local function dragged() self.Dragged = true; end draggable(brand, root, self.Conns, dragged); draggable(topbar, root, self.Conns, dragged); table.insert(self.Conns, root:GetPropertyChangedSignal("Position"):Connect(function() if not self.Dragged then return; end self.PosSaved = {x=root.Position.X.Offset,y=root.Position.Y.Offset}; self:_save(); end)); table.insert(self.Conns, UserInputService.InputBegan:Connect(function(input, processed) if (self.Destroyed or self.Listening) then return; end if UserInputService:GetFocusedTextBox() then return; end if ((input.KeyCode == self.Key) and (input.KeyCode ~= Enum.KeyCode.Unknown)) then self:SetOpen(not self.Open); return; end if processed then return; end for _, b in ipairs(self.Binds) do if (b.key and ((input.KeyCode == b.key) or (input.UserInputType == b.key))) then task.spawn(b.fire); end end end)); if UserInputService.TouchEnabled then local fab = new("TextButton", {Text="",BackgroundColor3=T.Panel,AutoButtonColor=false,Position=UDim2.new(0, 16, 0.5, -22),Size=UDim2.fromOffset(44, 44),Parent=gui}, {corner(22)}); self:bind(fab, "BackgroundColor3", "Panel"); bstroke(self, fab, "Stroke", 1, 0); self:icon(fab, opts.Icon or "layout-grid", 18, "Text"); draggable(fab, fab, self.Conns); local downAt; fab.InputBegan:Connect(function(i) if ((i.UserInputType == Enum.UserInputType.Touch) or (i.UserInputType == Enum.UserInputType.MouseButton1)) then downAt = fab.AbsolutePosition; end end); fab.MouseButton1Up:Connect(function() if (downAt and ((fab.AbsolutePosition - downAt).Magnitude < 6)) then self:SetOpen(not self.Open); end end); end local acc, frames, ping = 0, 0, 0; table.insert(self.Conns, RunService.RenderStepped:Connect(function(dt) if (not self.Open or self.Destroyed) then return; end acc, frames = acc + dt, frames + 1; if (acc >= 0.5) then local fps = math.floor((frames / acc) + 0.5); acc, frames = 0, 0; pcall(function() ping = math.floor(game:GetService("Stats").Network.ServerStatsItem["Data Ping"]:GetValue() + 0.5); end); self.StatLbl.Text = string.format("%d fps · %d ms", fps, ping); end end)); table.insert(self.Redraws, function() self:_crumb(); end); fit(); self:_place(); self.Scale.Scale = self:_scale() * 0.97; self:_blur(self.BlurPref); self:_fxSync(); self:_dockBuild(opts); if (opts.Settings ~= false) then task.defer(function() if not self.Destroyed then self:_settingsTab(); end end); end task.defer(function() if not self.Destroyed then self:_boot(opts); end end); return self; end; Window._crumb = function(self) local tab = self.Current; local function hex(c) return "#" .. toHex(c); end self.Crumb.Text = string.format('<font color="%s">%s</font><font color="%s"> / </font>%s', hex(self.T.SubText), self.Title, hex(self.T.Muted), (tab and tab.Name) or ""); end; Window._boot = function(self, opts) self.Booted = true; self.Scale.Scale = self:_scale() * 0.97; tween(self.Scale, 0.3, {Scale=self:_scale()}); tween(self.Body, 0.25, {GroupTransparency=0}); local function ready() if self.Current then self:_movePill(self.Current, true); end end if ((opts.Loading ~= true) and (type(opts.Loading) ~= "table")) then ready(); return; end local T = self.T; local sp = new("CanvasGroup", {BackgroundColor3=T.Background,Size=UDim2.fromScale(1, 1),ZIndex=100,Parent=self.Body}); self:bind(sp, "BackgroundColor3", "Background"); local t1 = text({Text=self.Title,FontFace=F.SemiBold,TextSize=15,TextXAlignment=Enum.TextXAlignment.Center,AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.fromScale(0.5, 0.46),Size=UDim2.new(1, 0, 0, 20),Parent=sp}); self:bind(t1, "TextColor3", "Text"); local step = text({Text="",TextSize=11,TextXAlignment=Enum.TextXAlignment.Center,AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.new(0.5, 0, 0.46, 24),Size=UDim2.new(1, 0, 0, 14),Parent=sp}); self:bind(step, "TextColor3", "Muted"); local track = new("Frame", {AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.new(0.5, 0, 0.46, 46),Size=UDim2.fromOffset(160, 2),Parent=sp}, {corner(1)}); self:bind(track, "BackgroundColor3", "Stroke"); local fill = new("Frame", {Size=UDim2.fromScale(0, 1),Parent=track}, {corner(1)}); self:bind(fill, "BackgroundColor3", "Accent"); task.spawn(function() local steps = ((type(opts.Loading) == "table") and opts.Loading.Steps) or {"Starting","Applying theme","Ready"}; for i, s in ipairs(steps) do step.Text = s; tween(fill, 0.3, {Size=UDim2.fromScale(i / #steps, 1)}); task.wait(0.28); end if self.Destroyed then return; end tween(sp, 0.3, {GroupTransparency=1}); task.wait(0.3); sp:Destroy(); ready(); end); end; Window._blur = function(self, on) if (on and not self.BlurActive and self.Open) then self.BlurActive = true; U.blur(true, 12); elseif (not on and self.BlurActive) then self.BlurActive = false; U.blur(false); end end; Window.SetBlur = function(self, v) self.BlurPref = v == true; self:_blur(self.BlurPref and self.Open); self:_save(); end; Window.SetOpen = function(self, open) if (self.Destroyed or (self.Open == open)) then return; end self.Open = open; self:_dockSync(); if open then if not self.PosSaved then self:_place(); end self.Root.Visible = true; self.Scale.Scale = self:_scale() * 0.97; self.Body.GroupTransparency = 1; tween(self.Scale, 0.28, {Scale=self:_scale()}); tween(self.Body, 0.2, {GroupTransparency=0}); tween(self.Shadow, 0.25, {ImageTransparency=0.7}); self:_blur(self.BlurPref); else if self.ListenCancel then self.ListenCancel(); end self.Listening = false; tween(self.Scale, 0.2, {Scale=(self:_scale() * 0.97)}, Enum.EasingStyle.Quad); tween(self.Body, 0.18, {GroupTransparency=1}); tween(self.Shadow, 0.18, {ImageTransparency=1}); self:_blur(false); task.delay(0.22, function() if (not self.Open and not self.Destroyed) then self.Root.Visible = false; end end); end end; Window.Toggle = function(self) self:SetOpen(not self.Open); end; Window.SetSidebar = function(self, collapsed) self.SideCollapsed = collapsed == true; local w = (self.SideCollapsed and SIDE_CLOSED) or SIDE_OPEN; tween(self.Sidebar, 0.3, {Size=UDim2.new(0, w, 1, 0)}); tween(self.Content, 0.3, {Position=UDim2.fromOffset(w, 0),Size=UDim2.new(1, -w, 1, 0)}); for _, l in ipairs(self.SideLabels) do if l.Parent then tween(l, 0.2, {TextTransparency=((self.SideCollapsed and 1) or 0)}); end end task.delay(0.35, function() if self.Current then self:_movePill(self.Current, true); end end); end; Window.Destroy = function(self) if self.Destroyed then return; end self:_flush(); self.Destroyed = true; self:_fxStop(); self:_dockSync(); if (self.DockSlot and U.dockSlots) then U.dockSlots[self.DockSlot] = nil; end for i = #(U.windows or {}), 1, -1 do if (U.windows[i] == self) then table.remove(U.windows, i); end end if U.refreshActive then pcall(U.refreshActive); end for _, c in ipairs(self.Conns) do pcall(function() c:Disconnect(); end); end self:_blur(false); if self.OnDestroy then pcall(self.OnDestroy); end tween(self.Scale, 0.2, {Scale=(self:_scale() * 0.97)}); tween(self.Body, 0.18, {GroupTransparency=1}); tween(self.Shadow, 0.18, {ImageTransparency=1}); task.delay(0.25, function() self.Gui:Destroy(); end); end; Window._movePill = function(self, tab, instant) local btn = tab and tab.Btn; if (not btn or not btn.Parent) then return; end if not btn.Visible then self.Pill.Visible = false; return; end local scale = math.max(self.Scale.Scale, 0.01); local y = (btn.AbsolutePosition.Y - self.TabInner.AbsolutePosition.Y) / scale; self.Pill.Visible = true; tween(self.Pill, (instant and 0) or 0.22, {Position=UDim2.fromOffset(8, y),Size=UDim2.new(1, -16, 0, btn.AbsoluteSize.Y / scale)}); end; Window.Tab = function(self, opts) if (type(opts) == "string") then opts = {Name=opts}; end local tab = setmetatable({}, Tab); tab.Window = self; tab.Name = opts.Name or "Tab"; tab.Desc = opts.Desc or opts.Description or ""; tab.IconName = opts.Icon or "layout-grid"; tab.Group = opts.Group; tab.Rows = {}; self.OrderCount = self.OrderCount + 1; tab.Order = self.OrderCount; local T = self.T; local btn = new("TextButton", {Text="",AutoButtonColor=false,BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 32),LayoutOrder=tab.Order,ZIndex=2,Parent=self.TabInner}); tab.IconImg = self:icon(btn, tab.IconName, 15, T.SubText, {AnchorPoint=Vector2.new(0, 0.5),Position=UDim2.new(0, 10, 0.5, 0)}); tab.NameLbl = text({Text=tab.Name,FontFace=F.Medium,TextSize=13,TextColor3=T.SubText,Position=UDim2.fromOffset(36, 0),Size=UDim2.new(1, -44, 1, 0),TextTruncate=Enum.TextTruncate.AtEnd,Parent=btn}); table.insert(self.SideLabels, tab.NameLbl); tab.Btn = btn; tab._paint = function(self, selected, hovered) local TT = self.Window.T; local c = ((selected or hovered) and TT.Text) or TT.SubText; tween(self.NameLbl, 0.12, {TextColor3=c}); tween(self.IconImg, 0.12, {ImageColor3=c}); end; table.insert(self.Redraws, function() tab:_paint(self.Current == tab); end); btn.MouseEnter:Connect(function() if (self.Current ~= tab) then tab:_paint(false, true); end end); btn.MouseLeave:Connect(function() if (self.Current ~= tab) then tab:_paint(false, false); end end); btn.MouseButton1Click:Connect(function() self:Select(tab); end); tab.Page = new("CanvasGroup", {Name=tab.Name,BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),Visible=false,GroupTransparency=1,Parent=self.Pages}); tab.Scroll = new("ScrollingFrame", {BackgroundTransparency=1,BorderSizePixel=0,Size=UDim2.fromScale(1, 1),CanvasSize=UDim2.new(),AutomaticCanvasSize=Enum.AutomaticSize.Y,ScrollBarThickness=2,ScrollBarImageColor3=T.Muted,ScrollingDirection=Enum.ScrollingDirection.Y,Parent=tab.Page}, {list(20),pad(18, 18, 16, 20)}); self:bind(tab.Scroll, "ScrollBarImageColor3", "Muted"); if tab.Group then table.insert(tab.Group.Tabs, tab); btn.Visible = tab.Group.Open; end table.insert(self.Tabs, tab); if not self.Current then self:Select(tab); end return tab; end; Window.Group = function(self, opts) if (type(opts) == "string") then opts = {Name=opts}; end local win = self; local group = {Window=self,Tabs={},Open=(opts.Open ~= false)}; self.OrderCount = self.OrderCount + 1; local head = new("TextButton", {Text="",AutoButtonColor=false,BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 26),LayoutOrder=self.OrderCount,ZIndex=2,Parent=self.TabInner}); local lbl = text({Text=string.upper(opts.Name or "Group"),FontFace=F.SemiBold,TextSize=10,Position=UDim2.fromOffset(10, 4),Size=UDim2.new(1, -36, 1, -4),Parent=head}); self:bind(lbl, "TextColor3", "Muted"); table.insert(self.SideLabels, lbl); local arrow = self:icon(head, "chevron-down", 12, "Muted", {AnchorPoint=Vector2.new(1, 0.5),Position=UDim2.new(1, -12, 0.5, 2)}); arrow.Rotation = (group.Open and 0) or -90; group.SetOpen = function(self, v) group.Open = v == true; tween(arrow, 0.2, {Rotation=((group.Open and 0) or -90)}); for _, t in ipairs(group.Tabs) do t.Btn.Visible = group.Open; end task.delay(0.05, function() if win.Current then win:_movePill(win.Current, true); end end); end; head.MouseButton1Click:Connect(function() group:SetOpen(not group.Open); end); group.Tab = function(self, o) if (type(o) == "string") then o = {Name=o}; end o.Group = group; return group.Window:Tab(o); end; return group; end; Window.Select = function(self, tab) if (type(tab) == "string") then for _, t in ipairs(self.Tabs) do if (t.Name == tab) then tab = t; break; end end end if ((type(tab) ~= "table") or (tab == self.Current)) then return; end if (tab.Group and not tab.Group.Open) then tab.Group:SetOpen(true); end local old = self.Current; self.Current = tab; if old then old:_paint(false, false); old.Page.Visible = false; end tab:_paint(true, false); if self.Booted then self:_movePill(tab); end tab.Page.Visible = true; tab.Page.GroupTransparency = 1; tab.Page.Position = UDim2.fromOffset(0, 8); tween(tab.Page, 0.22, {GroupTransparency=0,Position=UDim2.fromOffset(0, 0)}); self:_crumb(); end; Window._buildSearch = function(self) local T = self.T; local panel = new("Frame", {BackgroundColor3=T.Panel,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -10, 0, TOP_H - 4),Size=UDim2.fromOffset(280, 0),AutomaticSize=Enum.AutomaticSize.Y,Visible=false,ZIndex=60,Parent=self.Content}, {corner(8),pad(4, 4, 4, 4),list(1)}); self:bind(panel, "BackgroundColor3", "Panel"); bstroke(self, panel, "Stroke", 1, 0); self.SearchPanel = panel; local box, wrap = self.SearchBox, self.SearchWrap; local function clear() for _, c in ipairs(panel:GetChildren()) do if (c:IsA("TextButton") or c:IsA("TextLabel")) then c:Destroy(); end end end local function jump(entry) box.Text = ""; box:ReleaseFocus(); panel.Visible = false; self:Select(entry.tab); if (entry.sec and entry.sec.Collapsed) then entry.sec:SetCollapsed(false); end task.delay(0.45, function() if (not entry.row.Parent or self.Destroyed) then return; end local sc = entry.tab.Scroll; local s = math.max(self.Scale.Scale, 0.01); local y = (((entry.row.AbsolutePosition.Y - sc.AbsolutePosition.Y) / s) + sc.CanvasPosition.Y) - 24; tween(sc, 0.35, {CanvasPosition=Vector2.new(0, math.max(y, 0))}); self:_flash(entry.row); end); end local function refresh() local q = box.Text:lower(); clear(); if (q == "") then panel.Visible = false; return; end local found = 0; for _, e in ipairs(self.Index) do if (e.row.Parent and (e.name:lower():find(q, 1, true) or e.desc:lower():find(q, 1, true) or e.tab.Name:lower():find(q, 1, true))) then found = found + 1; if (found > 7) then break; end local b = new("TextButton", {Text="",AutoButtonColor=false,BackgroundColor3=self.T.Hover,BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 30),LayoutOrder=found,ZIndex=61,Parent=panel}, {corner(5)}); self:icon(b, e.tab.IconName, 14, "Muted", {AnchorPoint=Vector2.new(0, 0.5),Position=UDim2.new(0, 9, 0.5, 0),ZIndex=62}); local n = text({Text=e.name,FontFace=F.Medium,TextSize=12,Position=UDim2.fromOffset(32, 0),Size=UDim2.new(1, -110, 1, 0),TextTruncate=Enum.TextTruncate.AtEnd,ZIndex=62,Parent=b}); self:bind(n, "TextColor3", "Text"); local t = text({Text=e.tab.Name,TextSize=11,TextXAlignment=Enum.TextXAlignment.Right,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -9, 0, 0),Size=UDim2.fromOffset(70, 30),TextTruncate=Enum.TextTruncate.AtEnd,ZIndex=62,Parent=b}); self:bind(t, "TextColor3", "Muted"); b.MouseEnter:Connect(function() tween(b, 0.08, {BackgroundTransparency=0}); end); b.MouseLeave:Connect(function() tween(b, 0.12, {BackgroundTransparency=1}); end); b.MouseButton1Click:Connect(function() jump(e); end); end end if (found == 0) then local n = text({Text="No results",TextSize=12,TextXAlignment=Enum.TextXAlignment.Center,Size=UDim2.new(1, 0, 0, 30),ZIndex=61,Parent=panel}); self:bind(n, "TextColor3", "Muted"); end panel.Visible = true; end box:GetPropertyChangedSignal("Text"):Connect(refresh); box.Focused:Connect(function() tween(wrap, 0.22, {Size=UDim2.fromOffset(190, 28),BackgroundTransparency=0}); tween(self.SearchStroke, 0.15, {Transparency=0}); refresh(); end); box.FocusLost:Connect(function() tween(wrap, 0.2, {Size=UDim2.fromOffset(28, 28),BackgroundTransparency=1}); tween(self.SearchStroke, 0.15, {Transparency=1}); task.delay(0.15, function() panel.Visible = false; end); task.delay(0.25, function() if not box:IsFocused() then box.Visible = false; end end); end); local hit = new("TextButton", {Text="",BackgroundTransparency=1,Size=UDim2.fromOffset(28, 28),ZIndex=8,Parent=wrap}); hit.MouseButton1Click:Connect(function() self:FocusSearch(); end); hit.MouseEnter:Connect(function() if not box:IsFocused() then tween(wrap, 0.1, {BackgroundTransparency=0}); end end); hit.MouseLeave:Connect(function() if not box:IsFocused() then tween(wrap, 0.15, {BackgroundTransparency=1}); end end); end; Window.FocusSearch = function(self) if self.SearchBox then self.SearchBox.Visible = true; self.SearchBox:CaptureFocus(); end end; Window.Dialog = function(self, opts) opts = opts or {}; local T = self.T; local modal = new("CanvasGroup", {BackgroundColor3=Color3.new(0, 0, 0),BackgroundTransparency=0.5,Size=UDim2.fromScale(1, 1),GroupTransparency=1,Active=true,ZIndex=200,Parent=self.Body}); local card = new("Frame", {BackgroundColor3=T.Panel,AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.fromScale(0.5, 0.5),Size=UDim2.fromOffset(320, 0),AutomaticSize=Enum.AutomaticSize.Y,ZIndex=201,Parent=modal}, {corner(10),pad(18, 18, 16, 14),list(8)}); self:bind(card, "BackgroundColor3", "Panel"); bstroke(self, card, "Stroke", 1, 0); local cs = new("UIScale", {Scale=0.96,Parent=card}); local title = text({Text=(opts.Title or "Are you sure?"),FontFace=F.SemiBold,TextSize=14,Size=UDim2.new(1, 0, 0, 20),LayoutOrder=1,ZIndex=202,Parent=card}); self:bind(title, "TextColor3", "Text"); local msg = text({Text=(opts.Content or ""),TextSize=13,TextWrapped=true,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,LayoutOrder=2,ZIndex=202,Parent=card}); self:bind(msg, "TextColor3", "SubText"); local btns = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 40),LayoutOrder=3,ZIndex=202,Parent=card}, {list(8, Enum.FillDirection.Horizontal, Enum.HorizontalAlignment.Right, Enum.VerticalAlignment.Bottom)}); local closed = false; local function close() if closed then return; end closed = true; tween(modal, 0.18, {GroupTransparency=1}); tween(cs, 0.18, {Scale=0.97}); task.delay(0.22, function() modal:Destroy(); end); end for i, b in ipairs(opts.Buttons or {{Text="Close"}}) do local primary, danger = b.Style == "Primary", b.Style == "Danger"; local btn = new("TextButton", {Text=(b.Text or "OK"),FontFace=F.Medium,TextSize=12,AutoButtonColor=false,BackgroundColor3=((danger and T.Bad) or (primary and T.Accent) or T.Hover),TextColor3=((danger and Color3.new(1, 1, 1)) or (primary and T.OnAccent) or T.Text),Size=UDim2.fromOffset(math.max(72, (#(b.Text or "OK") * 8) + 28), 30),LayoutOrder=i,ZIndex=203,Parent=btns}, {corner(6)}); if (not primary and not danger) then self:bind(btn, "BackgroundColor3", "Hover"); self:bind(btn, "TextColor3", "Text"); bstroke(self, btn, "Stroke", 1, 0); elseif primary then self:bind(btn, "BackgroundColor3", "Accent"); self:bind(btn, "TextColor3", "OnAccent"); end btn.MouseEnter:Connect(function() tween(btn, 0.1, {BackgroundTransparency=0.15}); end); btn.MouseLeave:Connect(function() tween(btn, 0.15, {BackgroundTransparency=0}); end); btn.MouseButton1Click:Connect(function() close(); safeCall(b.Callback); end); end tween(modal, 0.2, {GroupTransparency=0}); tween(cs, 0.25, {Scale=1}); return {Close=close}; end; local ROW_H = 40; local function sstroke(win, parent, token, thickness, transparency) local s = stroke(win.T[token], thickness, transparency); s.Parent = parent; win:bind(s, "Color", token); return s; end local function newRow(sec, height, noHover) local win = sec.Window; sec.Items = sec.Items + 1; local f = new("Frame", {BackgroundColor3=win.T.Hover,BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, height or ROW_H),LayoutOrder=sec.Items,ClipsDescendants=true,Parent=sec.Content}); win:bind(f, "BackgroundColor3", "Hover"); local line = new("Frame", {BorderSizePixel=0,AnchorPoint=Vector2.new(0, 1),Position=UDim2.fromScale(0, 1),Size=UDim2.new(1, 0, 0, 1),ZIndex=3,Parent=f}); win:bind(line, "BackgroundColor3", "Stroke"); if not noHover then f.MouseEnter:Connect(function() tween(f, 0.1, {BackgroundTransparency=0.45}); end); f.MouseLeave:Connect(function() tween(f, 0.15, {BackgroundTransparency=1}); end); end table.insert(sec.Tab.Rows, f); sec.LastRow = f; return f; end local function newAutoRow(sec) local win = sec.Window; sec.Items = sec.Items + 1; local f = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,LayoutOrder=sec.Items,Parent=sec.Content}, {list(0)}); local body = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,LayoutOrder=1,Parent=f}, {pad(14, 14, 11, 11),list(3)}); local line = new("Frame", {BorderSizePixel=0,Size=UDim2.new(1, 0, 0, 1),LayoutOrder=2,Parent=f}); win:bind(line, "BackgroundColor3", "Stroke"); table.insert(sec.Tab.Rows, f); sec.LastRow = f; return f, body; end local function labels(win, parent, name, desc, rightSpace, icon, top) local left = 14; if icon then local iy = ((type(top) == "number") and top) or 20; win:icon(parent, icon, 15, "SubText", {AnchorPoint=Vector2.new(0, 0.5),Position=((top and UDim2.new(0, 14, 0, iy)) or UDim2.new(0, 14, 0.5, 0))}); left = 40; end local holder = new("Frame", {BackgroundTransparency=1,Position=UDim2.new(0, left, 0, 0),Size=UDim2.new(1, (-(rightSpace or 0) - left) - 12, (top and 0) or 1, (top and 40) or 0),Parent=parent}, {new("UIListLayout", {Padding=UDim.new(0, 1),VerticalAlignment=Enum.VerticalAlignment.Center,SortOrder=Enum.SortOrder.LayoutOrder})}); local title = text({Text=(name or ""),FontFace=F.Medium,TextSize=13,Size=UDim2.new(1, 0, 0, 17),TextTruncate=Enum.TextTruncate.AtEnd,LayoutOrder=1,Parent=holder}); win:bind(title, "TextColor3", "Text"); local sub; if (desc and (desc ~= "")) then sub = text({Text=desc,TextSize=12,TextWrapped=true,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,LayoutOrder=2,Parent=holder}); win:bind(sub, "TextColor3", "SubText"); end return holder, title, sub; end local function autoHeight(win, f, holder, minHeight) local function update() local s = math.max(win.Scale.Scale, 0.01); local h = 0; for _, c in ipairs(holder:GetChildren()) do if c:IsA("GuiObject") then h = h + (c.AbsoluteSize.Y / s) + 1; end end f.Size = UDim2.new(1, 0, 0, math.max(minHeight, h + 20)); end for _, c in ipairs(holder:GetChildren()) do if c:IsA("GuiObject") then c:GetPropertyChangedSignal("AbsoluteSize"):Connect(update); end end task.defer(update); end local function chip(win, parent, w, h) local c = new("Frame", {BackgroundColor3=win.T.Hover,AnchorPoint=Vector2.new(1, 0.5),Position=UDim2.new(1, -12, 0.5, 0),Size=UDim2.fromOffset(w, h or 26),Parent=parent}, {corner(6)}); win:bind(c, "BackgroundColor3", "Hover"); sstroke(win, c, "Stroke", 1, 0); return c; end Tab.Section = function(self, name, opts) opts = opts or {}; local win = self.Window; local sec = setmetatable({}, Section); sec.Window, sec.Tab, sec.Items, sec.Name = win, self, 0, name; self.Count = (self.Count or 0) + 1; sec.Frame = new("Frame", {BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,LayoutOrder=self.Count,Parent=self.Scroll}, {list(8)}); if (name and (name ~= "")) then local head = new("TextButton", {Text="",AutoButtonColor=false,BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 18),LayoutOrder=0,Parent=sec.Frame}); local lbl = text({Text=string.upper(name),FontFace=F.SemiBold,TextSize=11,Position=UDim2.fromOffset(2, 0),Size=UDim2.new(1, -24, 1, 0),Parent=head}); win:bind(lbl, "TextColor3", "Muted"); sec.Chevron = win:icon(head, "chevron-down", 12, "Muted", {AnchorPoint=Vector2.new(1, 0.5),Position=UDim2.new(1, -4, 0.5, 0)}); head.MouseEnter:Connect(function() tween(lbl, 0.1, {TextColor3=win.T.SubText}); end); head.MouseLeave:Connect(function() tween(lbl, 0.15, {TextColor3=win.T.Muted}); end); head.MouseButton1Click:Connect(function() sec:SetCollapsed(not sec.Collapsed); end); end sec.Layout = list(0); sec.Content = new("Frame", {BackgroundColor3=win.T.Element,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,ClipsDescendants=true,LayoutOrder=1,Parent=sec.Frame}, {corner(8),sec.Layout}); win:bind(sec.Content, "BackgroundColor3", "Element"); sstroke(win, sec.Content, "Stroke", 1, 0); if opts.Collapsed then task.defer(function() sec:SetCollapsed(true, true); end); end return sec; end; Section.SetCollapsed = function(self, v, instant) v = v == true; if (v == self.Collapsed) then return; end self.Collapsed = v; local c = self.Content; local s = math.max(self.Window.Scale.Scale, 0.01); local d = (instant and 0) or 0.25; if self.Chevron then tween(self.Chevron, d, {Rotation=((v and -90) or 0)}); end if v then self.LastHeight = c.AbsoluteSize.Y / s; c.AutomaticSize = Enum.AutomaticSize.None; c.Size = UDim2.new(1, 0, 0, self.LastHeight); tween(c, d, {Size=UDim2.new(1, 0, 0, 0)}).Completed:Connect(function() if self.Collapsed then c.Visible = false; end end); else local h = self.Layout.AbsoluteContentSize.Y / s; if (h < 1) then h = self.LastHeight or 40; end c.Visible = true; local t = tween(c, d, {Size=UDim2.new(1, 0, 0, h)}); t.Completed:Connect(function() if not self.Collapsed then c.AutomaticSize = Enum.AutomaticSize.Y; c.Size = UDim2.new(1, 0, 0, 0); end end); end end; local function defaultSection(tab) if not tab.Default then tab.Default = tab:Section(nil); end return tab.Default; end Section.Button = function(self, opts) local win = self.Window; local T = win.T; local style = opts.Style; local f = newRow(self, ROW_H); local click = new("TextButton", {Text="",BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),ZIndex=4,Parent=f}); local label = opts.ButtonText or opts.Text or "Run"; local w = math.max(54, (#label * 7) + 24); local holder, title = labels(win, f, opts.Name, opts.Desc, w + 4, opts.Icon); autoHeight(win, f, holder, ROW_H); local b = new("Frame", {AnchorPoint=Vector2.new(1, 0.5),Position=UDim2.new(1, -12, 0.5, 0),Size=UDim2.fromOffset(w, 26),ZIndex=2,Parent=f}, {corner(6)}); local bl = text({Text=label,FontFace=F.Medium,TextSize=12,TextXAlignment=Enum.TextXAlignment.Center,Size=UDim2.fromScale(1, 1),ZIndex=3,Parent=b}); local bs; local function paint() local TT = win.T; if (style == "Primary") then b.BackgroundColor3, bl.TextColor3 = TT.Accent, TT.OnAccent; elseif (style == "Danger") then b.BackgroundColor3, bl.TextColor3 = TT.Bad, Color3.new(1, 1, 1); else b.BackgroundColor3, bl.TextColor3 = TT.Hover, TT.Text; end end paint(); table.insert(win.Redraws, paint); if ((style ~= "Primary") and (style ~= "Danger")) then bs = sstroke(win, b, "Stroke", 1, 0); end click.MouseEnter:Connect(function() tween(b, 0.1, {BackgroundTransparency=0.12}); end); click.MouseLeave:Connect(function() tween(b, 0.15, {BackgroundTransparency=0}); end); click.MouseButton1Down:Connect(function() tween(b, 0.06, {BackgroundTransparency=0.3}); end); click.MouseButton1Up:Connect(function() tween(b, 0.12, {BackgroundTransparency=0.12}); end); click.MouseButton1Click:Connect(function() safeCall(opts.Callback); end); win:_index(self.Tab, opts.Name, opts.Desc, f, self); local obj = {}; obj.SetName = function(self, t) title.Text = t; end; obj.SetText = function(self, t) bl.Text = t; end; return obj; end; Section.Toggle = function(self, opts) local win = self.Window; local value = opts.Default == true; local locked = false; local f = newRow(self, ROW_H); local btn = new("TextButton", {Text="",BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),ZIndex=4,Parent=f}); local holder = labels(win, f, opts.Name, opts.Desc, 46, opts.Icon); autoHeight(win, f, holder, ROW_H); local track = new("Frame", {BackgroundColor3=win.T.Stroke,AnchorPoint=Vector2.new(1, 0.5),Position=UDim2.new(1, -14, 0.5, 0),Size=UDim2.fromOffset(30, 18),ZIndex=2,Parent=f}, {corner(9)}); local knob = new("Frame", {BackgroundColor3=win.T.Muted,AnchorPoint=Vector2.new(0, 0.5),Position=UDim2.new(0, 3, 0.5, 0),Size=UDim2.fromOffset(12, 12),ZIndex=3,Parent=track}, {corner(6)}); local function draw(instant) local TT = win.T; local d = (instant and 0) or 0.16; tween(track, d, {BackgroundColor3=((value and TT.Accent) or TT.Stroke)}); tween(knob, d, {Position=((value and UDim2.new(0, 15, 0.5, 0)) or UDim2.new(0, 3, 0.5, 0)),BackgroundColor3=((value and TT.OnAccent) or TT.Muted)}); end table.insert(win.Redraws, function() draw(true); end); local obj = {}; local listeners = {}; obj.Set = function(self, v, silent) if (locked and (v == true)) then return; end value = v == true; draw(); if not silent then safeCall(opts.Callback, value); end for _, fn in ipairs(listeners) do pcall(fn, value); end win:_save(); end; obj.Get = function(self) return value; end; obj.OnChanged = function(self, fn) table.insert(listeners, fn); end; table.insert(win.Toggles, {name=(opts.Name or "?"),sec=self,get=function() return value; end}); obj.Lock = function(self) locked = true; f.BackgroundTransparency = 0.5; if value then obj:Set(false); end end; obj.Unlock = function(self) locked = false; f.BackgroundTransparency = 1; end; local saved = win:_flag(opts.Flag, function() return value; end, function(v) obj:Set(v); end); if (saved ~= nil) then value = saved == true; end draw(true); btn.MouseButton1Click:Connect(function() if locked then return; end obj:Set(not value); end); f.MouseEnter:Connect(function() if not locked then tween(f, 0.1, {BackgroundTransparency=0.45}); end end); f.MouseLeave:Connect(function() tween(f, 0.15, {BackgroundTransparency=((locked and 0.5) or 1)}); end); win:_index(self.Tab, opts.Name, opts.Desc, f, self); safeCall(opts.Callback, value); return obj; end; Section.Slider = function(self, opts) local win = self.Window; local T = win.T; local min, max = opts.Min or 0, opts.Max or 100; local step = opts.Step or opts.Increment or 1; local suffix = opts.Suffix or ""; local value = math.clamp(opts.Default or min, min, max); local hasDesc = opts.Desc and (opts.Desc ~= ""); local f = newRow(self, (hasDesc and 66) or 54); local holder = labels(win, f, opts.Name, opts.Desc, 80, opts.Icon); holder.Size = UDim2.new(1, -((opts.Icon and 40) or 14) - 92, 0, (hasDesc and 46) or 32); local box = new("TextBox", {Text="",FontFace=F.Mono,TextSize=12,TextColor3=T.SubText,BackgroundColor3=T.Hover,BackgroundTransparency=1,TextXAlignment=Enum.TextXAlignment.Right,ClearTextOnFocus=false,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -10, 0, 4),Size=UDim2.fromOffset(76, 24),Parent=f}, {corner(5),pad(6, 6, 0, 0)}); win:bind(box, "TextColor3", "SubText"); win:bind(box, "BackgroundColor3", "Hover"); local track = new("Frame", {BackgroundColor3=T.Stroke,Position=UDim2.new(0, 14, 1, -17),Size=UDim2.new(1, -28, 0, 4),Parent=f}, {corner(2)}); win:bind(track, "BackgroundColor3", "Stroke"); local fill = new("Frame", {BackgroundColor3=T.Accent,Size=UDim2.fromScale(0, 1),Parent=track}, {corner(2)}); win:bind(fill, "BackgroundColor3", "Accent"); local knob = new("Frame", {BackgroundColor3=T.Text,AnchorPoint=Vector2.new(0.5, 0.5),Position=UDim2.fromScale(0, 0.5),Size=UDim2.fromOffset(12, 12),ZIndex=3,Parent=track}, {corner(6)}); win:bind(knob, "BackgroundColor3", "Text"); local obj = {}; local function draw(instant) local r = ((max > min) and ((value - min) / (max - min))) or 0; local d = (instant and 0) or 0.1; tween(fill, d, {Size=UDim2.fromScale(r, 1)}); tween(knob, d, {Position=UDim2.fromScale(r, 0.5)}); box.Text = fmt(value) .. suffix; end obj.Set = function(self, v, silent) v = tonumber(v); if not v then draw(); return; end v = math.clamp(round(v - min, step) + min, min, max); local changed = v ~= value; value = v; draw(); if (changed and not silent) then safeCall(opts.Callback, value); end if changed then win:_save(); end end; obj.Get = function(self) return value; end; local saved = win:_flag(opts.Flag, function() return value; end, function(v) obj:Set(v); end); if (type(saved) == "number") then value = math.clamp(saved, min, max); end draw(true); local dragging = false; local function fromX(x) local r = math.clamp((x - track.AbsolutePosition.X) / math.max(track.AbsoluteSize.X, 1), 0, 1); obj:Set(min + ((max - min) * r)); end local hit = new("TextButton", {Text="",BackgroundTransparency=1,Position=UDim2.new(0, 0, 1, -32),Size=UDim2.new(1, 0, 0, 32),ZIndex=4,Parent=f}); hit.InputBegan:Connect(function(input) if ((input.UserInputType == Enum.UserInputType.MouseButton1) or (input.UserInputType == Enum.UserInputType.Touch)) then dragging = true; tween(knob, 0.1, {Size=UDim2.fromOffset(14, 14)}); fromX(input.Position.X); end end); table.insert(win.Conns, UserInputService.InputChanged:Connect(function(input) if (dragging and ((input.UserInputType == Enum.UserInputType.MouseMovement) or (input.UserInputType == Enum.UserInputType.Touch))) then fromX(input.Position.X); end end)); table.insert(win.Conns, UserInputService.InputEnded:Connect(function(input) if (dragging and ((input.UserInputType == Enum.UserInputType.MouseButton1) or (input.UserInputType == Enum.UserInputType.Touch))) then dragging = false; tween(knob, 0.12, {Size=UDim2.fromOffset(12, 12)}); end end)); box.Focused:Connect(function() tween(box, 0.1, {BackgroundTransparency=0,TextColor3=win.T.Text}); end); box.FocusLost:Connect(function() tween(box, 0.15, {BackgroundTransparency=1,TextColor3=win.T.SubText}); local n = tonumber((box.Text:gsub("[^%d%.%-]", ""))); obj:Set(n or value); end); f.MouseEnter:Connect(function() tween(f, 0.1, {BackgroundTransparency=0.45}); end); f.MouseLeave:Connect(function() tween(f, 0.15, {BackgroundTransparency=1}); end); win:_index(self.Tab, opts.Name, opts.Desc, f, self); safeCall(opts.Callback, value); return obj; end; Section.Dropdown = function(self, opts) local win = self.Window; local T = win.T; local multi = opts.Multi == true; local options = opts.Options or {}; local value; if multi then value = {}; for _, v in ipairs(((type(opts.Default) == "table") and opts.Default) or {}) do value[v] = true; end else value = opts.Default; end local open = false; local f = newRow(self, ROW_H, true); local head = new("TextButton", {Text="",BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, ROW_H),ZIndex=4,Parent=f}); local holder = labels(win, f, opts.Name, nil, 150, opts.Icon, true); local sel = new("Frame", {BackgroundColor3=T.Hover,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -12, 0, 7),Size=UDim2.fromOffset(120, 26),ZIndex=2,Parent=f}, {corner(6)}); win:bind(sel, "BackgroundColor3", "Hover"); sstroke(win, sel, "Stroke", 1, 0); local shown = text({Text="",FontFace=F.Medium,TextSize=12,Position=UDim2.fromOffset(10, 0),Size=UDim2.new(1, -30, 1, 0),TextTruncate=Enum.TextTruncate.AtEnd,ZIndex=3,Parent=sel}); win:bind(shown, "TextColor3", "Text"); local chev = win:icon(sel, "chevron-down", 12, "Muted", {AnchorPoint=Vector2.new(1, 0.5),Position=UDim2.new(1, -8, 0.5, 0),ZIndex=3}); local searchable = #options > 7; local body = new("Frame", {BackgroundTransparency=1,Position=UDim2.fromOffset(10, ROW_H + 2),Size=UDim2.new(1, -20, 0, 0),Parent=f}); local search; if searchable then search = new("TextBox", {Text="",PlaceholderText="Filter",FontFace=F.Regular,TextSize=12,TextColor3=T.Text,PlaceholderColor3=T.Muted,TextXAlignment=Enum.TextXAlignment.Left,BackgroundColor3=T.Hover,ClearTextOnFocus=false,Size=UDim2.new(1, 0, 0, 26),Parent=body}, {corner(6),pad(10, 10, 0, 0)}); win:bind(search, "TextColor3", "Text"); win:bind(search, "PlaceholderColor3", "Muted"); win:bind(search, "BackgroundColor3", "Hover"); sstroke(win, search, "Stroke", 1, 0); end local listTop = (searchable and 32) or 0; local scroll = new("ScrollingFrame", {BackgroundTransparency=1,BorderSizePixel=0,Position=UDim2.fromOffset(0, listTop),Size=UDim2.new(1, 0, 0, 0),CanvasSize=UDim2.new(),AutomaticCanvasSize=Enum.AutomaticSize.Y,ScrollBarThickness=2,ScrollBarImageColor3=T.Muted,Parent=body}, {list(1)}); win:bind(scroll, "ScrollBarImageColor3", "Muted"); local obj = {}; local buttons = {}; local function display() local txt; if multi then local picked = {}; for _, o in ipairs(options) do if value[o] then table.insert(picked, tostring(o)); end end txt = ((#picked == 0) and "None") or ((#picked <= 2) and table.concat(picked, ", ")) or (#picked .. " selected"); else txt = ((value ~= nil) and tostring(value)) or "Select"; end shown.Text = txt; sel.Size = UDim2.fromOffset(math.clamp(shown.TextBounds.X + 38, 84, 200), 26); end local function paint() for o, b in pairs(buttons) do local on = (multi and value[o]) or (not multi and (value == o)); b.label.TextColor3 = (on and win.T.Text) or win.T.SubText; b.tick.ImageTransparency = (on and 0) or 1; end end table.insert(win.Redraws, paint); local function visibleCount() local n = 0; for _, b in pairs(buttons) do if b.btn.Visible then n = n + 1; end end return n; end local function layout(instant) local listH = math.min(visibleCount() * 29, 174); scroll.Size = UDim2.new(1, 0, 0, listH); local h = (open and (ROW_H + 2 + listTop + listH + 10)) or ROW_H; tween(f, (instant and 0) or 0.22, {Size=UDim2.new(1, 0, 0, h)}); tween(chev, (instant and 0) or 0.2, {Rotation=((open and 180) or 0)}); end local function fire() if multi then local picked = {}; for _, o in ipairs(options) do if value[o] then table.insert(picked, o); end end safeCall(opts.Callback, picked); else safeCall(opts.Callback, value); end end local function build() for _, b in pairs(buttons) do b.btn:Destroy(); end buttons = {}; for i, o in ipairs(options) do local b = new("TextButton", {Text="",AutoButtonColor=false,BackgroundColor3=T.Hover,BackgroundTransparency=1,Size=UDim2.new(1, -4, 0, 28),LayoutOrder=i,Parent=scroll}, {corner(5)}); win:bind(b, "BackgroundColor3", "Hover"); local lbl = text({Text=tostring(o),TextSize=12,TextColor3=T.SubText,Position=UDim2.fromOffset(10, 0),Size=UDim2.new(1, -34, 1, 0),TextTruncate=Enum.TextTruncate.AtEnd,Parent=b}); local tick = win:icon(b, "check", 13, "Accent", {AnchorPoint=Vector2.new(1, 0.5),Position=UDim2.new(1, -8, 0.5, 0)}); tick.ImageTransparency = 1; b.MouseEnter:Connect(function() tween(b, 0.08, {BackgroundTransparency=0.3}); end); b.MouseLeave:Connect(function() tween(b, 0.12, {BackgroundTransparency=1}); end); b.MouseButton1Click:Connect(function() if multi then value[o] = not value[o] or nil; else value = o; open = false; if search then search.Text = ""; end layout(); end display(); paint(); fire(); win:_save(); end); buttons[o] = {btn=b,label=lbl,tick=tick}; end paint(); end local function filter() if not search then return; end local q = search.Text:lower(); for o, b in pairs(buttons) do b.btn.Visible = (q == "") or (tostring(o):lower():find(q, 1, true) ~= nil); end if open then layout(); end end if search then search:GetPropertyChangedSignal("Text"):Connect(filter); end head.MouseButton1Click:Connect(function() open = not open; if (not open and search) then search.Text = ""; end layout(); end); head.MouseEnter:Connect(function() if not open then tween(f, 0.1, {BackgroundTransparency=0.45}); end end); head.MouseLeave:Connect(function() tween(f, 0.15, {BackgroundTransparency=1}); end); obj.Set = function(self, v, silent) if multi then value = {}; for _, x in ipairs(((type(v) == "table") and v) or {v}) do value[x] = true; end else value = v; end display(); paint(); if not silent then fire(); end win:_save(); end; obj.Get = function(self) if not multi then return value; end local picked = {}; for _, o in ipairs(options) do if value[o] then table.insert(picked, o); end end return picked; end; obj.Refresh = function(self, newOptions, keep) options = newOptions or {}; if not keep then if multi then value = {}; else value = nil; end end build(); display(); filter(); layout(true); end; obj.SetOpen = function(self, v) open = v == true; layout(); end; local saved = win:_flag(opts.Flag, function() return obj:Get(); end, function(v) obj:Set(v); end, function() local v = obj:Get(); if (v == nil) then return false; end return v; end); if (saved ~= nil) then if (multi and (type(saved) == "table")) then value = {}; for _, x in ipairs(saved) do value[x] = true; end elseif not multi then value = ((saved ~= false) and saved) or nil; end end build(); display(); layout(true); win:_index(self.Tab, opts.Name, opts.Desc, f, self); if ((multi and next(value)) or (not multi and (value ~= nil))) then fire(); end return obj; end; Section.Input = function(self, opts) local win = self.Window; local T = win.T; local f = newRow(self, ROW_H); local holder = labels(win, f, opts.Name, opts.Desc, 160, opts.Icon); autoHeight(win, f, holder, ROW_H); local wrap = chip(win, f, 150, 26); local box = new("TextBox", {Text=(opts.Default or ""),PlaceholderText=(opts.Placeholder or "Type here"),FontFace=F.Regular,TextSize=12,TextColor3=T.Text,PlaceholderColor3=T.Muted,ClearTextOnFocus=false,TextTruncate=Enum.TextTruncate.AtEnd,TextXAlignment=Enum.TextXAlignment.Left,BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),Parent=wrap}, {pad(9, 9, 0, 0)}); win:bind(box, "TextColor3", "Text"); win:bind(box, "PlaceholderColor3", "Muted"); local line = wrap:FindFirstChildOfClass("UIStroke"); box.Focused:Connect(function() tween(line, 0.12, {Color=win.T.SubText}); end); local obj = {}; local function clean(t) if opts.Numeric then return (t:gsub("[^%d%.%-]", "")); end return t; end obj.Set = function(self, t, silent) box.Text = clean(tostring(t or "")); if not silent then safeCall(opts.Callback, box.Text, true); end win:_save(); end; obj.Get = function(self) return box.Text; end; box.FocusLost:Connect(function(enter) tween(line, 0.15, {Color=win.T.Stroke}); box.Text = clean(box.Text); safeCall(opts.Callback, box.Text, enter); win:_save(); end); f.MouseEnter:Connect(function() tween(f, 0.1, {BackgroundTransparency=0.45}); end); f.MouseLeave:Connect(function() tween(f, 0.15, {BackgroundTransparency=1}); end); local saved = win:_flag(opts.Flag, function() return box.Text; end, function(v) obj:Set(v); end); if (type(saved) == "string") then box.Text = saved; end win:_index(self.Tab, opts.Name, opts.Desc, f, self); if (box.Text ~= "") then safeCall(opts.Callback, box.Text, true); end return obj; end; Section.Keybind = function(self, opts) local win = self.Window; local T = win.T; local key = opts.Default; local f = newRow(self, ROW_H); local holder = labels(win, f, opts.Name, opts.Desc, 90, opts.Icon); autoHeight(win, f, holder, ROW_H); local btnChip = chip(win, f, 56, 24); local line = btnChip:FindFirstChildOfClass("UIStroke"); local btn = new("TextButton", {Text=keyName(key),FontFace=F.Mono,TextSize=11,AutoButtonColor=false,BackgroundTransparency=1,Size=UDim2.fromScale(1, 1),Parent=btnChip}); win:bind(btn, "TextColor3", "SubText"); local function resize() tween(btnChip, 0.12, {Size=UDim2.fromOffset(math.max(44, btn.TextBounds.X + 20), 24)}); end btn:GetPropertyChangedSignal("Text"):Connect(resize); local bind = {key=key,sec=self}; self.Bind = self.Bind or bind; bind.fire = function() if opts.Callback then safeCall(opts.Callback, bind.key); end end; table.insert(win.Binds, bind); local obj = {}; obj.Set = function(self, k) if ((k == nil) or ((typeof(k) == "EnumItem") and ((k == Enum.KeyCode.Escape) or (k == Enum.KeyCode.Backspace)))) then k = nil; end if (opts.KeyboardOnly and (k ~= nil) and (k.EnumType ~= Enum.KeyCode)) then return; end key, bind.key = k, k; btn.Text = keyName(k); safeCall(opts.Changed, k); win:_save(); end; obj.Get = function(self) return key; end; btn.MouseButton1Click:Connect(function() if win.Listening then return; end win.Listening = true; btn.Text = "press a key"; tween(line, 0.1, {Color=win.T.Accent}); local c; local function stop() if c then c:Disconnect(); c = nil; end tween(line, 0.15, {Color=win.T.Stroke}); btn.Text = keyName(key); win.ListenCancel = nil; task.defer(function() win.Listening = false; end); end win.ListenCancel = stop; c = UserInputService.InputBegan:Connect(function(input) local k; if (input.UserInputType == Enum.UserInputType.Keyboard) then k = input.KeyCode; elseif (not opts.KeyboardOnly and ((input.UserInputType == Enum.UserInputType.MouseButton2) or (input.UserInputType == Enum.UserInputType.MouseButton3))) then k = input.UserInputType; else return; end stop(); obj:Set(k); end); end); f.MouseEnter:Connect(function() tween(f, 0.1, {BackgroundTransparency=0.45}); end); f.MouseLeave:Connect(function() tween(f, 0.15, {BackgroundTransparency=1}); end); local saved = win:_flag(opts.Flag, function() return key; end, function(v) obj:Set(v); end, function() return (key and key.Name) or "None"; end, function(name) if (name == "None") then return false; end local ok, k = pcall(function() return Enum.KeyCode[name]; end); if (ok and k) then return k; end if opts.KeyboardOnly then return nil; end ok, k = pcall(function() return Enum.UserInputType[name]; end); return (ok and k) or nil; end); if (saved == false) then key = nil; elseif saved then key = saved; end bind.key = key; btn.Text = keyName(key); win:_index(self.Tab, opts.Name, opts.Desc, f, self); return obj; end; Section.ColorPicker = function(self, opts) local win = self.Window; local T = win.T; local color = opts.Default or opts.Color or Color3.new(1, 1, 1); local h, s, v = color:ToHSV(); local open = false; local f = newRow(self, ROW_H, true); local head = new("TextButton", {Text="",BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, ROW_H),ZIndex=4,Parent=f}); labels(win, f, opts.Name, nil, 60, opts.Icon, true); local swatch = new("Frame", {BackgroundColor3=color,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -12, 0, 12),Size=UDim2.fromOffset(28, 16),ZIndex=2,Parent=f}, {corner(4)}); sstroke(win, swatch, "Stroke", 1, 0); local body = new("Frame", {BackgroundTransparency=1,Position=UDim2.new(0, 14, 0, ROW_H + 4),Size=UDim2.new(1, -28, 0, 134),Parent=f}); local sv = new("TextButton", {Text="",AutoButtonColor=false,BackgroundColor3=Color3.fromHSV(h, 1, 1),Size=UDim2.new(1, -96, 0, 104),Parent=body}, {corner(6)}); new("Frame", {BackgroundColor3=Color3.new(1, 1, 1),Size=UDim2.fromScale(1, 1),Parent=sv}, {corner(6),new("UIGradient", {Transparency=NumberSequence.new(0, 1)})}); new("Frame", {BackgroundColor3=Color3.new(0, 0, 0),Size=UDim2.fromScale(1, 1),Parent=sv}, {corner(6),new("UIGradient", {Rotation=90,Transparency=NumberSequence.new(1, 0)})}); local svDot = new("Frame", {BackgroundTransparency=1,AnchorPoint=Vector2.new(0.5, 0.5),Size=UDim2.fromOffset(10, 10),ZIndex=3,Parent=sv}, {corner(5),stroke(Color3.new(1, 1, 1), 2, 0)}); local hueKeys = {}; for i = 0, 6 do table.insert(hueKeys, ColorSequenceKeypoint.new(i / 6, Color3.fromHSV((i / 6) % 1, 1, 1))); end local hue = new("TextButton", {Text="",AutoButtonColor=false,BackgroundColor3=Color3.new(1, 1, 1),Position=UDim2.new(0, 0, 0, 114),Size=UDim2.new(1, -96, 0, 10),Parent=body}, {corner(5),new("UIGradient", {Color=ColorSequence.new(hueKeys)})}); local hueDot = new("Frame", {BackgroundColor3=Color3.new(1, 1, 1),AnchorPoint=Vector2.new(0.5, 0.5),Size=UDim2.fromOffset(6, 14),ZIndex=3,Parent=hue}, {corner(3)}); sstroke(win, hueDot, "Stroke", 1, 0); local preview = new("Frame", {BackgroundColor3=color,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, 0, 0, 0),Size=UDim2.fromOffset(84, 70),Parent=body}, {corner(6)}); sstroke(win, preview, "Stroke", 1, 0); local hex = new("TextBox", {Text=toHex(color),FontFace=F.Mono,TextSize=12,ClearTextOnFocus=false,BackgroundColor3=T.Hover,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, 0, 0, 78),Size=UDim2.fromOffset(84, 26),Parent=body}, {corner(6)}); win:bind(hex, "TextColor3", "Text"); win:bind(hex, "BackgroundColor3", "Hover"); sstroke(win, hex, "Stroke", 1, 0); local obj = {}; local function draw() color = Color3.fromHSV(h, s, v); sv.BackgroundColor3 = Color3.fromHSV(h, 1, 1); svDot.Position = UDim2.fromScale(s, 1 - v); hueDot.Position = UDim2.fromScale(h, 0.5); swatch.BackgroundColor3 = color; preview.BackgroundColor3 = color; hex.Text = toHex(color); end obj.Set = function(self, c, silent) if (typeof(c) ~= "Color3") then return; end h, s, v = c:ToHSV(); draw(); if not silent then safeCall(opts.Callback, color); end win:_save(); end; obj.Get = function(self) return color; end; local drag; local function update(pos) if (drag == "sv") then s = math.clamp((pos.X - sv.AbsolutePosition.X) / math.max(sv.AbsoluteSize.X, 1), 0, 1); v = 1 - math.clamp((pos.Y - sv.AbsolutePosition.Y) / math.max(sv.AbsoluteSize.Y, 1), 0, 1); elseif (drag == "hue") then h = math.clamp((pos.X - hue.AbsolutePosition.X) / math.max(hue.AbsoluteSize.X, 1), 0, 0.999); end draw(); safeCall(opts.Callback, color); win:_save(); end local function begin(which) return function(input) if ((input.UserInputType == Enum.UserInputType.MouseButton1) or (input.UserInputType == Enum.UserInputType.Touch)) then drag = which; update(input.Position); end end; end sv.InputBegan:Connect(begin("sv")); hue.InputBegan:Connect(begin("hue")); table.insert(win.Conns, UserInputService.InputChanged:Connect(function(input) if (drag and ((input.UserInputType == Enum.UserInputType.MouseMovement) or (input.UserInputType == Enum.UserInputType.Touch))) then update(input.Position); end end)); table.insert(win.Conns, UserInputService.InputEnded:Connect(function(input) if ((input.UserInputType == Enum.UserInputType.MouseButton1) or (input.UserInputType == Enum.UserInputType.Touch)) then drag = nil; end end)); hex.FocusLost:Connect(function() local c = fromHex(hex.Text); if c then obj:Set(c); else hex.Text = toHex(color); end end); head.MouseButton1Click:Connect(function() open = not open; tween(f, 0.22, {Size=UDim2.new(1, 0, 0, (open and (ROW_H + 148)) or ROW_H)}); end); head.MouseEnter:Connect(function() if not open then tween(f, 0.1, {BackgroundTransparency=0.45}); end end); head.MouseLeave:Connect(function() tween(f, 0.15, {BackgroundTransparency=1}); end); local saved = win:_flag(opts.Flag, function() return color; end, function(c) obj:Set(c); end, function() return toHex(color); end, fromHex); if saved then h, s, v = saved:ToHSV(); end draw(); win:_index(self.Tab, opts.Name, opts.Desc, f, self); safeCall(opts.Callback, color); return obj; end; Section.Label = function(self, opts) if (type(opts) == "string") then opts = {Text=opts}; end local win = self.Window; local f, body = newAutoRow(self); local lbl = text({Text=(opts.Text or ""),TextSize=12,TextWrapped=true,RichText=true,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,Parent=body}); win:bind(lbl, "TextColor3", "SubText"); local obj = {}; obj.Set = function(self, t) lbl.Text = tostring(t); end; obj.Get = function(self) return lbl.Text; end; return obj; end; Section.Paragraph = function(self, opts) local win = self.Window; local f, body = newAutoRow(self); local title = text({Text=(opts.Title or opts.Name or ""),FontFace=F.Medium,TextSize=13,Size=UDim2.new(1, 0, 0, 17),LayoutOrder=1,Parent=body}); win:bind(title, "TextColor3", "Text"); local msg = text({Text=(opts.Content or ""),TextSize=12,TextWrapped=true,RichText=true,Size=UDim2.new(1, 0, 0, 0),AutomaticSize=Enum.AutomaticSize.Y,LayoutOrder=2,Parent=body}); win:bind(msg, "TextColor3", "SubText"); local obj = {}; obj.Set = function(self, t) msg.Text = tostring(t); end; obj.SetTitle = function(self, t) title.Text = tostring(t); end; return obj; end; Section.Progress = function(self, opts) local win = self.Window; local f = newRow(self, 48, true); local holder = labels(win, f, opts.Name, nil, 90, opts.Icon, 15); holder.Size = UDim2.new(1, -((opts.Icon and 40) or 14) - 100, 0, 30); local pct = text({Text="0%",FontFace=F.Mono,TextSize=12,TextXAlignment=Enum.TextXAlignment.Right,AnchorPoint=Vector2.new(1, 0),Position=UDim2.new(1, -14, 0, 0),Size=UDim2.fromOffset(100, 30),Parent=f}); win:bind(pct, "TextColor3", "SubText"); local track = new("Frame", {BackgroundColor3=win.T.Stroke,Position=UDim2.new(0, 14, 1, -15),Size=UDim2.new(1, -28, 0, 3),Parent=f}, {corner(2)}); win:bind(track, "BackgroundColor3", "Stroke"); local fill = new("Frame", {BackgroundColor3=win.T.Accent,Size=UDim2.fromScale(0, 1),Parent=track}, {corner(2)}); win:bind(fill, "BackgroundColor3", "Accent"); local obj = {}; obj.Set = function(self, r, label) r = math.clamp(tonumber(r) or 0, 0, 1); tween(fill, 0.3, {Size=UDim2.fromScale(r, 1)}); pct.Text = label or (math.floor((r * 100) + 0.5) .. "%"); end; obj:Set(opts.Default or 0); win:_index(self.Tab, opts.Name, opts.Desc, f, self); return obj; end; Section.Stat = function(self, opts) local win = self.Window; local f = newRow(self, ROW_H, true); labels(win, f, opts.Name, nil, 130, opts.Icon); local val = text({Text=tostring(opts.Value or "-"),FontFace=F.SemiBold,TextSize=13,TextXAlignment=Enum.TextXAlignment.Right,AnchorPoint=Vector2.new(1, 0.5),Position=UDim2.new(1, -14, 0.5, 0),Size=UDim2.fromOffset(150, 20),Parent=f}); win:bind(val, "TextColor3", "Text"); local obj = {}; obj.Set = function(self, t) val.Text = tostring(t); end; win:_index(self.Tab, opts.Name, opts.Desc, f, self); return obj; end; Section.Divider = function(self) local f = newRow(self, 8, true); f.BackgroundColor3 = self.Window.T.Background; self.Window:bind(f, "BackgroundColor3", "Background"); f.BackgroundTransparency = 0; end; local ELEMENTS = {"Button","Toggle","Slider","Dropdown","Input","Keybind","ColorPicker","Label","Paragraph","Progress","Stat","Divider"}; for _, name in ipairs(ELEMENTS) do local make = Section[name]; Section[name] = function(sec, opts) sec.LastRow = nil; local obj = make(sec, opts); local dep = (type(opts) == "table") and opts.DependsOn; local row = sec.LastRow; if (row and (type(dep) == "table") and (type(dep.Get) == "function") and (type(dep.OnChanged) == "function")) then local want = opts.DependsValue; if (want == nil) then want = true; end local function sync() row.Visible = dep:Get() == want; end sync(); dep:OnChanged(sync); end return obj; end; end for _, name in ipairs(ELEMENTS) do Tab[name] = function(tab, opts) return Section[name](defaultSection(tab), opts); end; end local active = {gui=nil,panel=nil,sig=nil,loop=false}; local function activeLines() local lines, theme = {}, nil; for _, w in ipairs(U.windows or {}) do if (not w.Destroyed and w.ShowActive) then theme = theme or w.T; for _, t in ipairs(w.Toggles) do if ((t.sec.Tab.Name ~= "Settings") and t.get()) then local bind = t.sec.Bind; table.insert(lines, {name=t.name,key=((bind and bind.key and keyName(bind.key)) or "")}); end end end end return lines, theme; end local function renderActive() local lines, T = activeLines(); if not T then if active.gui then active.gui.Enabled = false; end return; end if (not active.gui or not active.gui.Parent) then active.gui = screenGui("VantaActive", 140); active.panel = new("Frame", {Position=UDim2.fromOffset(14, 64),Size=UDim2.fromOffset(190, 0),AutomaticSize=Enum.AutomaticSize.Y,BackgroundTransparency=0.06,Parent=active.gui}, {corner(8),pad(10, 10, 8, 8),list(3)}); active.stroke = stroke(T.Stroke, 1, 0); active.stroke.Parent = active.panel; active.conns = {}; draggable(active.panel, active.panel, active.conns); active.sig = nil; end active.gui.Enabled = true; local sig = (T.Panel and tostring(T.Panel)) or ""; for _, l in ipairs(lines) do sig = sig .. "|" .. l.name .. "=" .. l.key; end if (sig == active.sig) then return; end active.sig = sig; for _, c in ipairs(active.panel:GetChildren()) do if (c:IsA("TextLabel") or (c:IsA("Frame") and (c.Name == "Line"))) then c:Destroy(); end end active.panel.BackgroundColor3 = T.Panel; active.stroke.Color = T.Stroke; text({Text="ON",FontFace=F.SemiBold,TextSize=11,TextColor3=T.Muted,Size=UDim2.new(1, 0, 0, 14),LayoutOrder=0,Parent=active.panel}); if (#lines == 0) then text({Text="nothing is on",TextSize=12,TextColor3=T.Muted,Size=UDim2.new(1, 0, 0, 16),LayoutOrder=1,Parent=active.panel}); end for i, l in ipairs(lines) do local row = new("Frame", {Name="Line",BackgroundTransparency=1,Size=UDim2.new(1, 0, 0, 16),LayoutOrder=i,Parent=active.panel}); new("Frame", {BackgroundColor3=T.Good,AnchorPoint=Vector2.new(0, 0.5),Position=UDim2.new(0, 0, 0.5, 0),Size=UDim2.fromOffset(6, 6),Parent=row}, {corner(3)}); text({Text=l.name,TextSize=12,TextColor3=T.Text,Position=UDim2.fromOffset(12, 0),Size=UDim2.new(1, -60, 1, 0),TextTruncate=Enum.TextTruncate.AtEnd,Parent=row}); text({Text=l.key,FontFace=F.Mono,TextSize=11,TextColor3=T.SubText,TextXAlignment=Enum.TextXAlignment.Right,AnchorPoint=Vector2.new(1, 0),Position=UDim2.fromScale(1, 0),Size=UDim2.new(0, 46, 1, 0),Parent=row}); end end U.refreshActive = function() pcall(renderActive); if active.loop then return; end active.loop = true; task.spawn(function() while true do task.wait(0.4); pcall(renderActive); local any = false; for _, w in ipairs(U.windows or {}) do if (not w.Destroyed and w.ShowActive) then any = true; end end if not any then if active.gui then active.gui.Enabled = false; end active.loop = false; return; end end end); end; Window._settingsTab = function(self) local tab = self:Tab({Name="Settings",Icon="settings",Desc="Appearance and menu"}); tab.Btn.LayoutOrder = 9999; local look = tab:Section("Appearance"); local themeDrop = look:Dropdown({Name="Theme",Icon="sun-moon",Options=themeList(),Default=self.ThemeName,Callback=function(n) if (n and (n ~= self.ThemeName)) then self:SetTheme(n); end end}); if themeActive("Halloween") then look:Label("Limited time: the Halloween theme is here until " .. THEMES.Halloween.Limited.Ends .. "."); end local accentDrop = look:Dropdown({Name="Accent",Icon="droplet",Options=ACCENT_ORDER,Default=self.AccentName,Callback=function(n) if (n and (n ~= self.AccentName)) then self:SetAccent(n); end end}); table.insert(self.Redraws, function() themeDrop:Set(self.ThemeName, true); if self.AccentName then accentDrop:Set(self.AccentName, true); end end); look:Toggle({Name="Background blur",Desc="Softens the game behind the menu",Default=self.BlurPref,Callback=function(v) if (v ~= self.BlurPref) then self:SetBlur(v); end end}); look:Slider({Name="Interface scale",Min=70,Max=130,Step=5,Default=math.floor((self.UserScale * 100) + 0.5),Suffix="%",Callback=function(v) if (math.abs((v / 100) - self.UserScale) > 0.001) then self:SetScale(v / 100); end end}); look:Toggle({Name="Animations",Default=true,Callback=function(v) U.fast = not v; end}); local menu = tab:Section("Menu"); menu:Toggle({Name="Floating icon",Desc="A small button that brings the window back when it's hidden",Default=true,Flag="vanta_dock",Callback=function(v) self.DockOn = v == true; self:_dockSync(); end}); menu:Toggle({Name="Show what's on",Desc="A small on-screen list of every switch that's on, with its key",Default=false,Flag="vanta_active_list",Callback=function(v) self.ShowActive = v == true; U.refreshActive(); end}); menu:Button({Name="Reset window position",Desc="Forgets where you dragged it and picks a free spot again",ButtonText="Reset",Callback=function() self:ResetPosition(); end}); menu:Keybind({Name="Menu key",Desc="Shows and hides this window",Default=self.Key,KeyboardOnly=true,Changed=function(k) if k then self:SetKey(k); end end}); if self.ConfigPath then menu:Label("Settings are saved to workspace/" .. self.ConfigPath); end menu:Button({Name="Unload script",Desc="Turns everything off and closes this window",Style="Danger",ButtonText="Unload",Callback=function() self:Dialog({Title="Unload this script?",Content="Everything it started is turned off and the window closes.",Buttons={{Text="Cancel"},{Text="Unload",Style="Danger",Callback=function() self:Destroy(); end}}}); end}); end; return Vanta; end)(); local BPUI = (function(...) local Vanta = ...; local BPUI = {}; local lastWindow; local function convert(o) o = o or {}; local out = {}; for k, v in pairs(o) do out[k] = v; end out.Desc = o.Desc or o.Description; out.Step = o.Step or o.Increment; return out; end local function alias(obj) if (type(obj) ~= "table") then return obj; end obj.SetContent = obj.SetContent or obj.Set; obj.SetValue = obj.SetValue or obj.Set; obj.SetText = obj.SetText or obj.Set; return obj; end local Section = {}; Section.__index = Section; Section.AddToggle = function(self, o) return alias(self.v:Toggle(convert(o))); end; Section.AddSlider = function(self, o) return alias(self.v:Slider(convert(o))); end; Section.AddDropdown = function(self, o) return alias(self.v:Dropdown(convert(o))); end; Section.AddKeybind = function(self, o) return alias(self.v:Keybind(convert(o))); end; Section.AddButton = function(self, o) return alias(self.v:Button(convert(o))); end; Section.AddInput = function(self, o) return alias(self.v:Input(convert(o))); end; Section.AddTextbox = function(self, o) return alias(self.v:Input(convert(o))); end; Section.AddColorPicker = function(self, o) return alias(self.v:ColorPicker(convert(o))); end; Section.AddProgress = function(self, o) return alias(self.v:Progress(convert(o))); end; Section.AddDivider = function(self) return self.v:Divider(); end; Section.AddLabel = function(self, o) if (type(o) == "string") then o = {Text=o}; end return alias(self.v:Label(o or {})); end; Section.AddParagraph = function(self, o) o = o or {}; return alias(self.v:Paragraph({Title=(o.Title or o.Name),Content=(o.Content or o.Text)})); end; local Tab = {}; Tab.__index = Tab; Tab.CreateSection = function(self, o) local name = ((type(o) == "table") and (o.Name or o.Title)) or o; return setmetatable({v=self.v:Section(name)}, Section); end; local Window = {}; local function wrapTab(win, vtab) local t = setmetatable({v=vtab,Window=win}, Tab); win._tabs[vtab] = t; return t; end Window.__index = function(win, key) if (key == "_visible") then return win.v.Open; end if (key == "_activeTab") then return win._tabs[win.v.Current]; end return Window[key]; end; Window.CreateTab = function(self, o) if (type(o) == "string") then o = {Name=o}; end return wrapTab(self, self.v:Tab(convert(o))); end; Window.CreateGroup = function(self, o) if (type(o) == "string") then o = {Name=o}; end local win = self; local group = self.v:Group({Name=o.Name,Open=o.Open}); return {CreateTab=function(_, t) if (type(t) == "string") then t = {Name=t}; end return wrapTab(win, group:Tab(convert(t))); end,SetOpen=function(_, v) group:SetOpen(v); end}; end; Window.SelectTab = function(self, name) self.v:Select(name); end; Window.Notify = function(self, o) self.v:Notify(o); end; Window.Destroy = function(self) self.v:Destroy(); end; Window.Toggle = function(self) self.v:Toggle(); end; Window.SetOpen = function(self, v) self.v:SetOpen(v); end; BPUI.Windows = {}; BPUI.CreateWindow = function(self, o) o = o or {}; local gone; local version = o.Version or "1.6.4"; local v = Vanta:Window({Title=o.Title,Subtitle=((o.Subtitle and ("v" .. version .. " · " .. o.Subtitle)) or ("v" .. version)),Key=(o.ToggleKey or o.Key),Config=o.ConfigFolder,OnDestroy=function() if o.OnDestroy then o.OnDestroy(); end if BPUI.WindowGone then BPUI.WindowGone(gone); end end,Settings=(o.ShowSettings ~= false),Size=o.Size,Icon="cat",Theme=((Vanta.ThemeActive(o.Theme) and o.Theme) or (Vanta.ThemeActive("Halloween") and "Halloween") or nil)}); local win = setmetatable({v=v,_tabs={}}, Window); gone = v; table.insert(BPUI.Windows, v); lastWindow = win; return win; end; BPUI.Notify = function(self, o) if (lastWindow and not lastWindow.v.Destroyed) then lastWindow.v:Notify(o); else Vanta:Notify(o); end end; return BPUI; end)(Vanta); local SOURCES = {aba=[=[ local Players = game:GetService("Players") local UIS = game:GetService("UserInputService") local RunService = game:GetService("RunService") local TeleportService = game:GetService("TeleportService") local player = Players.LocalPlayer assert(player, "Run this script after Roblox has finished joining.") assert(type(loadstring) == "function", "Catn Hub needs loadstring.") local env = _G if type(getgenv) == "function" then local ok, value = pcall(getgenv) if ok and type(value) == "table" then env = value end end local KEY = "__BP_HUB_ABA" for _, key in ipairs({KEY, "__ABA_BLACK_FLASH_BPUI_V1", "__ABA_SPIRIT_GUN_ALL_TARGETS"}) do local previous = env[key] if type(previous) == "table" and type(previous.Destroy) == "function" then pcall(previous.Destroy) end end local BPUI = ... local executor = "Unknown executor" if type(identifyexecutor) == "function" then local ok, name, version = pcall(identifyexecutor) if ok then executor = tostring(name) .. (version and (" " .. tostring(version)) or "") end end local click = type(mouse1click) == "function" and mouse1click or nil local holdClick = type(mouse1press) == "function" and type(mouse1release) == "function" local canKeyClick = type(keyclick) == "function" local canAimMouse = type(mousemoveabs) == "function" local canCheckOwner = type(isnetworkowner) == "function" local focusCheck for _, name in ipairs({"isrbxactive", "isgameactive", "iswindowactive"}) do local fn = env[name] or getfenv()[name] if type(fn) == "function" then focusCheck = fn break end end local correctGame = game.PlaceId == 1458767429 local supported = click ~= nil and correctGame local alive = true local connections = {} local cleanups = {} local state = {executor = executor} local window local function connect(signal, callback) local connection = signal:Connect(callback) connections[#connections + 1] = connection return connection end local function onCleanup(fn) cleanups[#cleanups + 1] = fn end local function cleanup() if not alive then return end alive = false for _, connection in ipairs(connections) do connection:Disconnect() end table.clear(connections) for index = #cleanups, 1, -1 do pcall(cleanups[index]) end table.clear(cleanups) if env[KEY] == state then env[KEY] = nil end end state.Destroy = function() cleanup() if window then pcall(function() window:Destroy() end) end end env[KEY] = state local windowFocused = nil connect(UIS.WindowFocused, function() windowFocused = true end) connect(UIS.WindowFocusReleased, function() windowFocused = false end) local function isFocused() if focusCheck then local ok, value = pcall(focusCheck) if ok and type(value) == "boolean" then return value end end return windowFocused == true end local function canInput() return isFocused() and UIS:GetFocusedTextBox() == nil end local function hideWindow() if window then pcall(function() window:Hide() end) end end local function hiddenGuiParent() if type(gethui) == "function" then local ok, value = pcall(gethui) if ok and typeof(value) == "Instance" then return value end end return game:GetService("CoreGui") end local function gameAction(name) local scripts = player:FindFirstChild("PlayerScripts") local context = scripts and scripts:FindFirstChild("BaseContext") local action = context and context:FindFirstChild(name) if action and action:IsA("InputAction") then return action end end local function tapAction(name) local action = gameAction(name) if not action then return false end action:Fire(true) task.wait(0.03) action:Fire(false) return true end local function make(className, props, parent) local object = Instance.new(className) for key, value in pairs(props) do object[key] = value end object.Parent = parent return object end local timing = {frame = 1 / 60, frameJitter = 0, ping = 0.02, pingJitter = 0} connect(RunService.Heartbeat, function(dt) if dt <= 0 or dt > 1 then return end timing.frameJitter = timing.frameJitter + (0.12 * (math.abs(dt - timing.frame) - timing.frameJitter)) timing.frame = timing.frame + (0.12 * (dt - timing.frame)) end) local function samplePing() local ok, value = pcall(function() return player:GetNetworkPing() end) local measured = (ok and type(value) == "number" and value >= 0 and value < 2) and value or 0.02 timing.ping = timing.ping + (0.2 * (measured - timing.ping)) timing.pingJitter = timing.pingJitter + (0.2 * (math.abs(measured - timing.ping) - timing.pingJitter)) return measured end local Game = {} function Game.aliveRoot(model) if not model or not model.Parent then return nil end local humanoid = model:FindFirstChildOfClass("Humanoid") local root = model:FindFirstChild("HumanoidRootPart") if humanoid and root and humanoid.Health > 0 then return root, humanoid end return nil end function Game.ownRoot() return Game.aliveRoot(player.Character) end function Game.onAfkTeam(targetPlayer) local team = targetPlayer.Team return team ~= nil and string.find(string.lower(team.Name), "afk", 1, true) ~= nil end function Game.sameTeam(targetPlayer) if player.Team == nil or targetPlayer.Neutral then return false end if targetPlayer.Team == player.Team then return true end return targetPlayer.Team == nil and targetPlayer.TeamColor == player.TeamColor end function Game.teamAllows(targetPlayer, mode) if mode == "off" then return true end local same = Game.sameTeam(targetPlayer) if mode == "sameTeam" then return same end return not same end Game.teamModes = {["Enemies only"] = "enemies", ["Same team only"] = "sameTeam", Off = "off"} Game.teamModeOptions = {"Enemies only", "Same team only", "Off"} function Game.chargeFraction(targetPlayer) local charge = targetPlayer:FindFirstChild("Charge") if not charge then return 0 end local ok, value = pcall(function() return charge.Value / math.max(charge.MaxValue, 1) end) return ok and math.clamp(value, 0, 1) or 0 end function Game.stat(targetPlayer, name) local stats = targetPlayer:FindFirstChild("Stats") local value = stats and stats:FindFirstChild(name) return value and value:IsA("ValueBase") and tonumber(value.Value) or 0 end function Game.isBlocking(character) local blocking = character and character:FindFirstChild("Blocking") return blocking ~= nil and blocking:IsA("BoolValue") and blocking.Value end function Game.usingSkill(character) local skill = character and character:FindFirstChild("UsingSkill") if skill and skill:IsA("StringValue") then local name = skill.Value:match("^%s*(.-)%s*$") if name ~= "" then return name end end return nil end function Game.characterName(targetPlayer) local character = targetPlayer.Character return (character and character:GetAttribute("LastLoadedChar")) or targetPlayer:GetAttribute("LastLoadedChar") or "none" end local function moveSlot(move) local moveConfig = move:FindFirstChild(".Config") if not moveConfig then return nil end for _, child in ipairs(moveConfig:GetChildren()) do local number = tonumber(string.match(child.Name, "^Slot(%d+)$")) if number then return number end end return nil end local function moveProgress(move) local value = move:GetAttribute("COOLDOWN") return type(value) == "number" and math.clamp(value / 20, 0, 1) or 1 end function Game.moves(targetPlayer) local backpack = targetPlayer:FindFirstChildOfClass("Backpack") local list = {} if not backpack then return list end for _, move in ipairs(backpack:GetChildren()) do if move:IsA("Configuration") then local progress = moveProgress(move) list[#list + 1] = {name = move.Name, slot = moveSlot(move) or 99, progress = progress, ready = progress >= 1} end end table.sort(list, function(a, b) if a.slot ~= b.slot then return a.slot < b.slot end return a.name < b.name end) return list end function Game.ownMoveReady(index) local backpack = player:FindFirstChildOfClass("Backpack") if not backpack then return true end for _, move in ipairs(backpack:GetChildren()) do if move:IsA("Configuration") and moveSlot(move) == index then return moveProgress(move) >= 1 end end local playerGui = player:FindFirstChildOfClass("PlayerGui") local button = playerGui and playerGui:FindFirstChild("HUD") and playerGui.HUD:FindFirstChild("Moves") and playerGui.HUD.Moves:FindFirstChild(tostring(index)) local moveName = button and button:GetAttribute("MoveName") local move = type(moveName) == "string" and backpack:FindFirstChild(moveName) return not move or moveProgress(move) >= 1 end local yuji = { blackFlash = supported, blackFlashLast = "waiting for move 2", blackFlashClicks = 0, divergent = supported, divergentLast = "waiting for move 1", divergentClicks = 0, skull = false, skullLast = "off", skullClicks = 0, } state.Yuji = yuji local function divergentDelay() local measured = samplePing() local frameOverhead = math.max(0, timing.frame - 1 / 60) local delay = math.clamp(0.22 + timing.ping * 0.5 + timing.pingJitter * 0.5 + frameOverhead + timing.frameJitter * 0.5, 0.18, 0.36) return delay, measured end local function humanDelay(maxMs) return math.random() * maxMs / 1000 end local characterConnections = {} local function bindYuji(character) for _, connection in ipairs(characterConnections) do connection:Disconnect() end table.clear(characterConnections) local function hook(signal, callback) characterConnections[#characterConnections + 1] = signal:Connect(callback) end local divergentToken = 0 hook(character:GetAttributeChangedSignal("UsingDivergentBlow"), function() divergentToken = divergentToken + 1 local token = divergentToken if character:GetAttribute("UsingDivergentBlow") ~= true or not yuji.divergent then return end hideWindow() local delay, ping = divergentDelay() delay = delay + humanDelay(30) - 0.015 yuji.divergentLast = string.format("timing %.0fms (ping %.0fms)", delay * 1000, ping * 1000) task.delay(delay, function() if not alive or not yuji.divergent or player.Character ~= character or token ~= divergentToken or character:GetAttribute("UsingDivergentBlow") ~= true or not Game.aliveRoot(character) then return end if not canInput() then yuji.divergentLast = "skipped (roblox not focused)" return end local ok, reason = pcall(function() if holdClick then mouse1press() task.delay(0.12, function() pcall(mouse1release) end) else click() end end) if ok then yuji.divergentClicks = yuji.divergentClicks + 1 yuji.divergentLast = string.format("clicked after %.0fms (ping %.0fms)", delay * 1000, ping * 1000) else yuji.divergentLast = "click failed: " .. tostring(reason) end end) end) local blackFlashArmed, blackFlashToken, skullToken = false, 0, 0 hook(character.ChildAdded, function(child) if child.Name == "UsingSkill" and child:IsA("StringValue") then local skill = Game.usingSkill(character) blackFlashToken = blackFlashToken + 1 blackFlashArmed = skill == "Black Flash" if blackFlashArmed then if yuji.blackFlash then hideWindow() end local token = blackFlashToken task.delay(1.2, function() if token == blackFlashToken then blackFlashArmed = false end end) end if skill == "Skull Smash" and yuji.skull and supported then skullToken = skullToken + 1 local token = skullToken yuji.skullLast = "timing (1.5s)" hideWindow() task.delay(1.5 + humanDelay(40), function() if not alive or not yuji.skull or token ~= skullToken or player.Character ~= character or Game.usingSkill(character) ~= "Skull Smash" or not Game.aliveRoot(character) then return end if not canInput() then yuji.skullLast = "skipped (roblox not focused)" return end local ok, reason = pcall(click) if ok then yuji.skullClicks = yuji.skullClicks + 1 yuji.skullLast = "clicked" else yuji.skullLast = "click failed: " .. tostring(reason) end end) end elseif child.Name == "Action" and blackFlashArmed then blackFlashArmed = false if not alive or not yuji.blackFlash or not supported or player.Character ~= character or Game.usingSkill(character) ~= "Black Flash" or not Game.aliveRoot(character) then return end if not canInput() then yuji.blackFlashLast = "skipped (roblox not focused)" return end local wait = humanDelay(35) task.delay(wait, function() if not alive or not yuji.blackFlash then return end local ok, reason = pcall(click) if ok then yuji.blackFlashClicks = yuji.blackFlashClicks + 1 yuji.blackFlashLast = string.format("clicked %.0fms after the cue", wait * 1000) else yuji.blackFlashLast = "click failed: " .. tostring(reason) end end) end end) end onCleanup(function() for _, connection in ipairs(characterConnections) do connection:Disconnect() end table.clear(characterConnections) end) local nanami = {enabled = supported, last = "waiting", hits = 0} state.Nanami = nanami do local TARGET = 0.7 local current, clicked = nil, setmetatable({}, {__mode = "k"}) local windows = setmetatable({}, {__mode = "k"}) local function aiming() local character = player.Character return character ~= nil and character:GetAttribute("NANAMIAIM") == true end connect(workspace.DescendantAdded, function(descendant) if descendant.Name == "NanamiCutGUI" and nanami.enabled and aiming() then current = descendant end end) connect(RunService.Heartbeat, function() local gui = current if not gui then return end if not alive or not nanami.enabled or not supported or not gui.Parent or clicked[gui] or not aiming() then if not gui.Parent then current = nil end return end local cutter = gui:FindFirstChild("MainBar") and gui.MainBar:FindFirstChild("Cutter") if not cutter then return end hideWindow() local x = cutter.Position.X.Scale windows[gui] = windows[gui] or (0.004 + math.random() * 0.012) if math.abs(TARGET - x) > windows[gui] then return end clicked[gui] = true if not canInput() then nanami.last = "skipped (roblox not focused)" return end local ok, reason = pcall(click) if ok then nanami.hits = nanami.hits + 1 nanami.last = string.format("hit at %.3f", x) else nanami.last = "click failed: " .. tostring(reason) end end) end local anyBlackFlash = {enabled = supported, last = "waiting", clicks = 0} state.AnyBlackFlash = anyBlackFlash do local DIVE_START, DIVE_FLOOR, DIVE_RESET = 40, 15, 65 local diving, clicked, minFov, lastFov = false, false, 70, 70 connect(RunService.RenderStepped, function() local camera = workspace.CurrentCamera if not camera then return end local fov = camera.FieldOfView if not diving then if fov < DIVE_START and fov < lastFov then diving, clicked, minFov = true, false, fov if anyBlackFlash.enabled then hideWindow() end end else if fov < minFov then minFov = fov elseif not clicked and minFov < DIVE_FLOOR and fov > minFov + 0.25 then clicked = true if alive and anyBlackFlash.enabled and supported then if not canInput() then anyBlackFlash.last = "skipped (roblox not focused)" else local wait = humanDelay(30) task.delay(wait, function() if not alive or not anyBlackFlash.enabled then return end local ok, reason = pcall(click) if ok then anyBlackFlash.clicks = anyBlackFlash.clicks + 1 anyBlackFlash.last = string.format("clicked at fov %.1f, +%.0fms", fov, wait * 1000) else anyBlackFlash.last = "click failed: " .. tostring(reason) end end) end end end if fov >= DIVE_RESET then diving = false end end lastFov = fov end) end local kokushibo = {enabled = false, available = false, last = "waiting", hits = 0} state.Kokushibo = kokushibo do local remote = game:GetService("ReplicatedStorage"):FindFirstChild("KokushiboCheck") local original if remote and type(getcallbackvalue) == "function" then local ok, fn = pcall(getcallbackvalue, remote, "OnClientInvoke") if ok and type(fn) == "function" then original = fn end end kokushibo.available = original ~= nil and supported if kokushibo.available then local function rightClick() local context = player:FindFirstChild("PlayerScripts") and player.PlayerScripts:FindFirstChild("BaseContext") local action = context and context:FindFirstChild("Move5") if not (action and action:IsA("InputAction")) then return false end action:Fire(true) task.wait(0.05) action:Fire(false) return true end remote.OnClientInvoke = function(a1, a2, ...) local ours = false if alive and kokushibo.enabled and type(a1) == "number" and type(a2) == "number" and a2 > 0 then ours = true local lead, window = (a1 - a2) * 2, a2 * 2 local at = lead + window * (0.25 + math.random() * 0.45) task.delay(at, function() if not alive or not kokushibo.enabled then return end if rightClick() then kokushibo.last = string.format("pressed %.2fs into a %.2fs window", at - lead, window) else kokushibo.last = "couldn't find the right-click action" end end) end local result = original(a1, a2, ...) if ours and result == true then kokushibo.hits = kokushibo.hits + 1 end return result end onCleanup(function() pcall(function() remote.OnClientInvoke = original end) end) end end local yusuke = {enabled = correctGame and canCheckOwner, available = correctGame and canCheckOwner, teamMode = "enemies", last = "waiting for a gun move", shots = 0} state.Yusuke = yusuke if yusuke.available then local armedUntil = 0 local active = {} local function restore(ball, velocity) if ball.Parent then pcall(function() ball.AssemblyLinearVelocity = velocity end) end end onCleanup(function() for ball, velocity in pairs(active) do restore(ball, velocity) end table.clear(active) end) local function sweep(ball, character, root) local velocity = ball.AssemblyLinearVelocity active[ball] = velocity local ok, reason = pcall(function() local live = workspace:FindFirstChild("Live") if not live then return end local targets = {} for _, model in ipairs(live:GetChildren()) do local targetRoot, humanoid = Game.aliveRoot(model) local targetPlayer = Players:GetPlayerFromCharacter(model) if model ~= character and targetRoot and (not targetPlayer or Game.teamAllows(targetPlayer, yusuke.teamMode)) then targets[#targets + 1] = {root = targetRoot, humanoid = humanoid, distance = (targetRoot.Position - root.Position).Magnitude} end end table.sort(targets, function(a, b) return a.distance < b.distance end) local started, visited = os.clock(), 0 for _, target in ipairs(targets) do if not alive or not yusuke.enabled or not ball.Parent or player.Character ~= character or os.clock() - started > 20 then break end if target.root.Parent and target.humanoid.Health > 0 then for _ = 1, 5 do if not ball.Parent or not target.root.Parent then break end ball.CFrame = target.root.CFrame ball.AssemblyLinearVelocity = Vector3.zero task.wait(0.03) end visited = visited + 1 end end yusuke.last = "hit " .. visited .. "/" .. #targets .. " targets" end) restore(ball, velocity) active[ball] = nil if not ok then yusuke.last = "stopped: " .. tostring(reason) end end local function onBall(ball) if not alive or not yusuke.enabled or os.clock() > armedUntil then return end if ball.Name ~= "Ball" or not ball:IsA("BasePart") or ball.Anchored then return end local character = player.Character local root = Game.aliveRoot(character) if not root or (ball.Position - root.Position).Magnitude > 25 then return end local ok, owned = pcall(isnetworkowner, ball) if not ok or not owned then yusuke.last = "skipped (no ownership)" return end armedUntil = 0 yusuke.shots = yusuke.shots + 1 task.spawn(sweep, ball, character, root) end local thrownConnection local function watchThrown(folder) if thrownConnection then thrownConnection:Disconnect() end thrownConnection = connect(folder.ChildAdded, onBall) end if workspace:FindFirstChild("Thrown") then watchThrown(workspace.Thrown) end connect(workspace.ChildAdded, function(child) if child.Name == "Thrown" then watchThrown(child) end end) local function bindGun(character) connect(character.ChildAdded, function(child) if child.Name ~= "UsingSkill" or not child:IsA("StringValue") then return end local skill = Game.usingSkill(character) local gunMove = skill == "Spirit Gun" or skill == "Demon Gun" local isYusuke = character:GetAttribute("LastLoadedChar") == "Yusuke Urameshi" armedUntil = (yusuke.enabled and isYusuke and gunMove) and (os.clock() + 3) or 0 end) end if player.Character then bindGun(player.Character) end connect(player.CharacterAdded, bindGun) else yusuke.enabled = false yusuke.last = "not available (needs isnetworkowner)" end local krillin = {enabled = correctGame, teamMode = "enemies", fallback = false, volleyGap = 0.35, holdTime = 0.40, volleys = 0, last = "waiting for kiblast"} state.Krillin = krillin do local seen = setmetatable({}, {__mode = "k"}) local volleyTarget, lastCatch = nil, -math.huge local function candidates(applyTeam) local list = {} for _, targetPlayer in ipairs(Players:GetPlayers()) do if targetPlayer ~= player then local root = Game.aliveRoot(targetPlayer.Character) if root and (not applyTeam or Game.teamAllows(targetPlayer, krillin.teamMode)) then list[#list + 1] = root end end end return list end local function rollTarget() local list = candidates(true) if #list == 0 and krillin.fallback then list = candidates(false) end volleyTarget = #list > 0 and list[math.random(1, #list)] or nil lastCatch = os.clock() krillin.volleys = krillin.volleys + 1 krillin.last = volleyTarget and ("volley " .. krillin.volleys .. " -> " .. volleyTarget.Parent.Name) or "no target" return volleyTarget end local function liveTarget() if volleyTarget and Game.aliveRoot(volleyTarget.Parent) then return volleyTarget end return nil end local function hold(part) RunService.Heartbeat:Wait() local stopAt = os.clock() + krillin.holdTime while alive and krillin.enabled and part.Parent and os.clock() < stopAt do local target = liveTarget() or rollTarget() if not target then break end part.AssemblyLinearVelocity = Vector3.zero part.AssemblyAngularVelocity = Vector3.zero part.CFrame = target.CFrame RunService.Heartbeat:Wait() end end connect(workspace.DescendantAdded, function(part) if not krillin.enabled or seen[part] or not part:IsA("BasePart") then return end if not string.find(string.lower(part.Name), "kiblast", 1, true) then return end seen[part] = true if not liveTarget() or os.clock() - lastCatch > krillin.volleyGap then rollTarget() else lastCatch = os.clock() end task.spawn(hold, part) end) end local farm = { enabled = false, target = "none", last = "off", attacks = {["1"] = true, ["2"] = true, ["3"] = true, ["4"] = true, M1 = true, Mode = false}, teamMode = "enemies", skipAfk = true, priority = "Nearest", avoidBlocking = true, avoidModeReady = false, maxRange = 0, stayOnTarget = true, onlyReady = true, sticky = true, aimCamera = true, standoff = 3, position = "Behind", } state.Farm = farm do local current local lastRetarget = 0 local lastModePress = -math.huge local positions = { Behind = function(root, d) return root.Position - root.CFrame.LookVector * d end, ["Behind + above"] = function(root, d) return root.Position - root.CFrame.LookVector * d + Vector3.new(0, 4, 0) end, Above = function(root, d) return root.Position + Vector3.new(0, d + 3, 0) end, Side = function(root, d) return root.Position + root.CFrame.RightVector * d end, Front = function(root, d) return root.Position + root.CFrame.LookVector * d end, } farm.positionOptions = {"Behind", "Behind + above", "Above", "Side", "Front"} local scores = { ["Nearest"] = function(info) return info.distance end, ["Lowest HP"] = function(info) return info.health end, ["Lowest HP %"] = function(info) return info.health / math.max(info.maxHealth, 1) end, ["Most damage"] = function(info) return -info.damage end, } farm.priorityOptions = {"Nearest", "Lowest HP", "Lowest HP %", "Most damage"} local function eligible(targetPlayer) return targetPlayer ~= player and not (farm.skipAfk and Game.onAfkTeam(targetPlayer)) and Game.teamAllows(targetPlayer, farm.teamMode) end local function choose() local ownRoot = Game.ownRoot() if not ownRoot then return nil end local score = scores[farm.priority] or scores.Nearest local best, bestTier, bestScore for _, targetPlayer in ipairs(Players:GetPlayers()) do if eligible(targetPlayer) then local character = targetPlayer.Character local root, humanoid = Game.aliveRoot(character) if root then local distance = (root.Position - ownRoot.Position).Magnitude if farm.maxRange <= 0 or distance <= farm.maxRange then local tier = 0 if farm.avoidBlocking and Game.isBlocking(character) then tier = tier + 1 end if farm.avoidModeReady and Game.chargeFraction(targetPlayer) >= 1 then tier = tier + 1 end local value = score({distance = distance, health = humanoid.Health, maxHealth = humanoid.MaxHealth, damage = Game.stat(targetPlayer, "Damage")}) if not best or tier < bestTier or (tier == bestTier and value < bestScore) then best = {root = root, name = targetPlayer.Name, player = targetPlayer} bestTier, bestScore = tier, value end end end end end return best end farm.Preview = function() local best = choose() return best and best.name or nil end local function stillValid(target) return target ~= nil and Game.aliveRoot(target.root.Parent) ~= nil and target.player.Parent == Players and not (farm.skipAfk and Game.onAfkTeam(target.player)) end local function updateTarget() if not stillValid(current) then if os.clock() - lastRetarget >= 0.25 then current = choose() lastRetarget = os.clock() else current = nil end elseif not farm.stayOnTarget and os.clock() - lastRetarget >= 1 then lastRetarget = os.clock() current = choose() or current end farm.target = current and current.name or "none" farm.targetPlayer = current and current.player or nil end farm.Retarget = function() current = nil end local function stick(targetRoot) local root = Game.ownRoot() if not root or not targetRoot.Parent then return end local compute = positions[farm.position] or positions.Behind root.CFrame = CFrame.lookAt(compute(targetRoot, farm.standoff), targetRoot.Position) root.AssemblyLinearVelocity = Vector3.zero if farm.aimCamera then local camera = workspace.CurrentCamera if camera then camera.CFrame = CFrame.lookAt(camera.CFrame.Position, targetRoot.Position) end end end farm.ModeReady = function() return player:FindFirstChild("NoAwaken") == nil and Game.chargeFraction(player) >= 1 end local function tryMode() if not farm.attacks.Mode or os.clock() - lastModePress < 2 or not farm.ModeReady() then return false end lastModePress = os.clock() local context = player:FindFirstChild("PlayerScripts") and player.PlayerScripts:FindFirstChild("BaseContext") local action = context and context:FindFirstChild("UseMode") if action and action:IsA("InputAction") then action:Fire(true) task.wait(0.06) action:Fire(false) elseif canKeyClick then keyclick(0x47) end return true end farm.SetEnabled = function(value) farm.enabled = value == true and alive current = nil farm.last = farm.enabled and "running" or "off" end connect(RunService.Heartbeat, function() if not farm.enabled or not Game.ownRoot() then return end updateTarget() if current and farm.sticky then stick(current.root) end end) task.spawn(function() while alive do if farm.enabled then if not Game.ownRoot() then current = nil farm.target, farm.last = "none", "waiting to respawn" elseif not gameAction("MouseClick") and not canInput() then farm.last = "paused (roblox not focused)" else updateTarget() if not current then farm.last = "no targets" pcall(tryMode) else if not farm.sticky then stick(current.root) end RunService.Heartbeat:Wait() local actions = {} local ok, reason = pcall(function() if tryMode() then actions[#actions + 1] = "G" end local useActions = gameAction("MouseClick") ~= nil for index = 1, 4 do if farm.attacks[tostring(index)] and (not farm.onlyReady or Game.ownMoveReady(index)) then if useActions and tapAction("Move" .. index) then actions[#actions + 1] = tostring(index) elseif canKeyClick and canInput() then keyclick(0x30 + index) actions[#actions + 1] = tostring(index) end end end if farm.attacks.M1 then if useActions then tapAction("MouseClick") actions[#actions + 1] = "M1" elseif click and canInput() then local camera = workspace.CurrentCamera if camera and canAimMouse then mousemoveabs(math.max(1, math.floor(camera.ViewportSize.X * 0.82)), math.max(1, math.floor(camera.ViewportSize.Y * 0.5))) end click() actions[#actions + 1] = "M1" end end end) if not ok then farm.last = "input failed: " .. tostring(reason) elseif #actions > 0 then farm.last = "on " .. current.name .. " (" .. table.concat(actions, " ") .. ")" else farm.last = "on " .. current.name .. " (waiting for cooldowns)" end end end task.wait(0.15) else task.wait(0.25) end end end) onCleanup(function() farm.enabled = false current = nil end) end local autoBlock = {enabled = false, range = 14, hold = 0.45, skipGuardbreaks = true, whileFarming = false, last = "off", blocks = 0} state.AutoBlock = autoBlock do local CollectionService = game:GetService("CollectionService") local holdUntil, holding, pressedAt = 0, false, 0 local watched = setmetatable({}, {__mode = "k"}) local lastOwnAttack = -math.huge for _, name in ipairs({"MouseClick", "Move1", "Move2", "Move3", "Move4", "Move5"}) do local action = gameAction(name) if action then connect(action.Pressed, function() lastOwnAttack = os.clock() end) end end local function myRoot() return Game.ownRoot() end local function isEnemy(model) if model == player.Character then return false end local owner = Players:GetPlayerFromCharacter(model) if not owner then return true end return not Game.sameTeam(owner) end local function breaksGuard(model, skill) local owner = Players:GetPlayerFromCharacter(model) local backpack = owner and owner:FindFirstChildOfClass("Backpack") local move = backpack and backpack:FindFirstChild(skill) return move ~= nil and CollectionService:HasTag(move, "Guardbreaks") end local function trigger(model, root, seconds, reach, why) if not autoBlock.enabled or not alive then return end local mine = myRoot() if not mine or (root.Position - mine.Position).Magnitude > reach then return end if not isEnemy(model) then return end if not autoBlock.whileFarming and farm.enabled then return end holdUntil = math.max(holdUntil, os.clock() + seconds) autoBlock.last = why end local function watch(model) if watched[model] or model == player.Character then return end local humanoid = model:FindFirstChildOfClass("Humanoid") local root = model:FindFirstChild("HumanoidRootPart") local animator = humanoid and humanoid:FindFirstChildOfClass("Animator") if not (animator and root) then return end watched[model] = true connect(animator.AnimationPlayed, function(track) if track.Looped or os.clock() - lastOwnAttack < 0.5 then return end trigger(model, root, autoBlock.hold, autoBlock.range, "blocking an attack from " .. model.Name) end) connect(model.ChildAdded, function(child) if child.Name ~= "UsingSkill" or not child:IsA("StringValue") then return end task.defer(function() local skill = Game.usingSkill(model) if not skill then return end if autoBlock.skipGuardbreaks and breaksGuard(model, skill) then autoBlock.last = skill .. " breaks guard, not blocking" return end trigger(model, root, 0.8, autoBlock.range * 2, "blocking " .. skill) end) end) end local live = workspace:FindFirstChild("Live") if live then for _, model in ipairs(live:GetChildren()) do pcall(watch, model) end connect(live.ChildAdded, function(model) task.defer(function() pcall(watch, model) end) end) end local function setBlock(on) local action = gameAction("Block") if action then action:Fire(on) end end connect(RunService.Heartbeat, function() local want = autoBlock.enabled and alive and os.clock() < holdUntil and myRoot() ~= nil local character = player.Character local blocking = character and Game.isBlocking(character) if want and not holding then holding, pressedAt = true, os.clock() setBlock(true) autoBlock.blocks = autoBlock.blocks + 1 elseif not want and holding then holding = false setBlock(false) elseif want and holding and not blocking and os.clock() - pressedAt > 0.2 then setBlock(false) setBlock(true) pressedAt = os.clock() end end) autoBlock.SetEnabled = function(value) autoBlock.enabled = value == true and alive autoBlock.last = autoBlock.enabled and "watching" or "off" if not autoBlock.enabled and holding then holding = false setBlock(false) end end onCleanup(function() autoBlock.enabled = false if holding then holding = false setBlock(false) end end) end local rejoin = {enabled = false, loader = "", last = "off"} state.Rejoin = rejoin do local GuiService = game:GetService("GuiService") local busy = false local function go(message) if busy or not rejoin.enabled or not alive then return end busy = true rejoin.last = "disconnected: " .. tostring(message):sub(1, 60) task.wait(1) if rejoin.loader ~= "" and type(queue_on_teleport) == "function" then pcall(queue_on_teleport, rejoin.loader) end for attempt = 1, 10 do if not alive then break end rejoin.last = "rejoining (try " .. attempt .. ")" pcall(function() TeleportService:Teleport(game.PlaceId, player) end) task.wait(8) end busy = false end connect(GuiService.ErrorMessageChanged, function(message) if message and message ~= "" then task.spawn(go, message) end end) end local COLORS = { barBack = Color3.fromRGB(20, 20, 24), ready = Color3.fromRGB(110, 220, 120), charging = Color3.fromRGB(240, 170, 60), mode = Color3.fromRGB(150, 110, 240), modeReady = Color3.fromRGB(255, 215, 70), hpLow = Color3.fromRGB(235, 70, 70), hpHigh = Color3.fromRGB(110, 220, 120), text = Color3.fromRGB(230, 230, 230), dim = Color3.fromRGB(160, 160, 160), } local function makeBar(parent, height, order) local back = make("Frame", {BackgroundColor3 = COLORS.barBack, BackgroundTransparency = 0.25, BorderSizePixel = 0, Size = UDim2.new(1, 0, 0, height), LayoutOrder = order or 0}, parent) make("UICorner", {CornerRadius = UDim.new(0, 2)}, back) local fill = make("Frame", {BorderSizePixel = 0, Size = UDim2.fromScale(1, 1)}, back) make("UICorner", {CornerRadius = UDim.new(0, 2)}, fill) return back, fill end local function makeText(parent, props) props.BackgroundTransparency = 1 props.Font = props.Font or Enum.Font.Gotham props.TextStrokeTransparency = props.TextStrokeTransparency or 0.4 props.TextColor3 = props.TextColor3 or COLORS.text return make("TextLabel", props, parent) end local function makeMoveRows(parent, count, firstOrder, nameWidth, textSize) local rows = {} for index = 1, count do local row = make("Frame", {BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, textSize + 1), LayoutOrder = firstOrder + index, Visible = false}, parent) local label = makeText(row, {Size = UDim2.new(nameWidth, -4, 1, 0), TextSize = textSize, TextXAlignment = Enum.TextXAlignment.Right, TextTruncate = Enum.TextTruncate.AtEnd}) local back, fill = makeBar(row, 5) back.AnchorPoint = Vector2.new(1, 0.5) back.Position = UDim2.fromScale(1, 0.5) back.Size = UDim2.new(1 - nameWidth, 0, 0, 5) rows[index] = {row = row, label = label, fill = fill} end return rows end local function paintMoves(rows, moves) for index, row in ipairs(rows) do local move = moves[index] row.row.Visible = move ~= nil if move then row.label.Text = move.name row.label.TextColor3 = move.ready and COLORS.text or COLORS.dim row.fill.Size = UDim2.fromScale(move.progress, 1) row.fill.BackgroundColor3 = move.ready and COLORS.ready or COLORS.charging end end end local function healthColor(fraction) return COLORS.hpLow:Lerp(COLORS.hpHigh, fraction) end local esp = { enabled = false, shown = 0, outline = true, fill = true, labels = true, distance = true, healthBar = true, modeBar = true, cooldowns = true, hideTeammates = true, hideAfk = true, teamColors = true, limitDistance = false, maxDistance = 1500, enemyColor = Color3.fromRGB(235, 87, 87), allyColor = Color3.fromRGB(87, 180, 235), } state.ESP = esp do local container = make("Folder", {Name = "BPHubESP"}, hiddenGuiParent()) local entries = {} onCleanup(function() container:Destroy() table.clear(entries) end) local function removeEntry(targetPlayer) local entry = entries[targetPlayer] if not entry then return end entry.highlight:Destroy() entry.billboard:Destroy() entries[targetPlayer] = nil end local function getEntry(targetPlayer) if entries[targetPlayer] then return entries[targetPlayer] end local highlight = make("Highlight", {DepthMode = Enum.HighlightDepthMode.AlwaysOnTop, Enabled = false}, container) local billboard = make("BillboardGui", {AlwaysOnTop = true, Enabled = false, Size = UDim2.fromOffset(150, 120), StudsOffset = Vector3.new(0, 2.6, 0), SizeOffset = Vector2.new(0, 0.5), LightInfluence = 0, ResetOnSpawn = false}, container) local holder = make("Frame", {BackgroundTransparency = 1, Size = UDim2.fromScale(1, 1)}, billboard) make("UIListLayout", {SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 2), VerticalAlignment = Enum.VerticalAlignment.Bottom}, holder) local entry = {highlight = highlight, billboard = billboard} entry.name = makeText(holder, {Size = UDim2.new(1, 0, 0, 14), LayoutOrder = 1, Font = Enum.Font.GothamBold, TextSize = 13, TextStrokeTransparency = 0.35}) entry.healthBack, entry.healthFill = makeBar(holder, 5, 2) entry.modeBack, entry.modeFill = makeBar(holder, 3, 3) entry.healthText = makeText(holder, {Size = UDim2.new(1, 0, 0, 11), LayoutOrder = 4, TextSize = 10}) entry.moves = makeMoveRows(holder, 5, 10, 0.62, 10) entries[targetPlayer] = entry return entry end local function hideAll() for _, entry in pairs(entries) do entry.highlight.Enabled = false entry.billboard.Enabled = false end end local function paint(entry, targetPlayer, character, root, humanoid, distance) local teammate = Game.sameTeam(targetPlayer) local color = teammate and esp.allyColor or esp.enemyColor if esp.teamColors and targetPlayer.Team and not Game.onAfkTeam(targetPlayer) then color = targetPlayer.TeamColor.Color end local highlight = entry.highlight highlight.Adornee = character highlight.Enabled = esp.outline or esp.fill highlight.OutlineColor, highlight.FillColor = color, color highlight.OutlineTransparency = esp.outline and 0 or 1 highlight.FillTransparency = esp.fill and 0.7 or 1 local showBillboard = esp.labels or esp.healthBar or esp.modeBar or esp.cooldowns entry.billboard.Adornee = character:FindFirstChild("Head") or root entry.billboard.Enabled = showBillboard if not showBillboard then return end local mode = Game.chargeFraction(targetPlayer) entry.modeBack.Visible = esp.modeBar entry.modeFill.Size = UDim2.fromScale(mode, 1) entry.modeFill.BackgroundColor3 = mode >= 1 and COLORS.modeReady or COLORS.mode local name = targetPlayer.DisplayName if esp.modeBar and mode >= 1 then name = name .. (" [MODE]") end if esp.distance then name = name .. (string.format(" [%dm]", math.floor(distance + 0.5))) end entry.name.Visible = esp.labels entry.name.Text = name entry.name.TextColor3 = color local hp = math.clamp(humanoid.Health / math.max(humanoid.MaxHealth, 1), 0, 1) entry.healthBack.Visible = esp.healthBar entry.healthText.Visible = esp.healthBar entry.healthFill.Size = UDim2.fromScale(hp, 1) entry.healthFill.BackgroundColor3 = healthColor(hp) entry.healthText.Text = string.format("%d / %d", math.floor(humanoid.Health + 0.5), math.floor(humanoid.MaxHealth + 0.5)) paintMoves(entry.moves, esp.cooldowns and Game.moves(targetPlayer) or {}) end local wasEnabled = false task.spawn(function() while alive do if esp.enabled then wasEnabled = true local ok, reason = pcall(function() local camera = workspace.CurrentCamera local origin = camera and camera.CFrame.Position or Vector3.zero local shown = 0 for _, targetPlayer in ipairs(Players:GetPlayers()) do if targetPlayer ~= player then local character = targetPlayer.Character local root, humanoid = Game.aliveRoot(character) local distance = root and (root.Position - origin).Magnitude or math.huge local visible = root ~= nil and not (esp.hideTeammates and Game.sameTeam(targetPlayer)) and not (esp.hideAfk and Game.onAfkTeam(targetPlayer)) and not (esp.limitDistance and distance > esp.maxDistance) if visible then paint(getEntry(targetPlayer), targetPlayer, character, root, humanoid, distance) shown = shown + 1 elseif entries[targetPlayer] then entries[targetPlayer].highlight.Enabled = false entries[targetPlayer].billboard.Enabled = false end end end esp.shown = shown end) if not ok then warn("[Catn Hub ESP] " .. tostring(reason)) end elseif wasEnabled then wasEnabled = false esp.shown = 0 hideAll() end task.wait(0.1) end end) connect(Players.PlayerRemoving, removeEntry) end local panel = {enabled = false, range = 150, subject = nil} state.Panel = panel do local gui = make("ScreenGui", {Name = "BPHubPanel", ResetOnSpawn = false, IgnoreGuiInset = true, DisplayOrder = 8000, ZIndexBehavior = Enum.ZIndexBehavior.Sibling}, hiddenGuiParent()) onCleanup(function() gui:Destroy() end) local frame = make("Frame", {Size = UDim2.fromOffset(230, 0), Position = UDim2.new(0, 24, 0.5, -75), BackgroundColor3 = Color3.fromRGB(18, 18, 24), BackgroundTransparency = 0.15, BorderSizePixel = 0, Visible = false, AutomaticSize = Enum.AutomaticSize.Y}, gui) make("UICorner", {CornerRadius = UDim.new(0, 8)}, frame) make("UIStroke", {Color = Color3.fromRGB(143, 112, 236), Transparency = 0.5, Thickness = 1}, frame) make("UIPadding", {PaddingTop = UDim.new(0, 8), PaddingBottom = UDim.new(0, 8), PaddingLeft = UDim.new(0, 10), PaddingRight = UDim.new(0, 10)}, frame) make("UIListLayout", {SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 3)}, frame) local title = makeText(frame, {Size = UDim2.new(1, 0, 0, 16), LayoutOrder = 1, Font = Enum.Font.GothamBold, TextSize = 14, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd}) local subtitle = makeText(frame, {Size = UDim2.new(1, 0, 0, 12), LayoutOrder = 2, TextSize = 11, TextColor3 = COLORS.dim, TextXAlignment = Enum.TextXAlignment.Left}) local _, healthFill = makeBar(frame, 7, 3) local healthText = makeText(frame, {Size = UDim2.new(1, 0, 0, 12), LayoutOrder = 4, TextSize = 11, TextXAlignment = Enum.TextXAlignment.Left}) local _, modeFill = makeBar(frame, 4, 5) local modeText = makeText(frame, {Size = UDim2.new(1, 0, 0, 12), LayoutOrder = 6, TextSize = 11, TextXAlignment = Enum.TextXAlignment.Left}) local moveRows = makeMoveRows(frame, 5, 10, 0.6, 11) local dragging, dragStart, startPosition connect(frame.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging, dragStart, startPosition = true, input.Position, frame.Position end end) connect(UIS.InputChanged, function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then local delta = input.Position - dragStart frame.Position = UDim2.new(startPosition.X.Scale, startPosition.X.Offset + delta.X, startPosition.Y.Scale, startPosition.Y.Offset + delta.Y) end end) connect(UIS.InputEnded, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = false end end) local function nearestEnemy() local ownRoot = Game.ownRoot() if not ownRoot then return nil end local best, bestDistance for _, targetPlayer in ipairs(Players:GetPlayers()) do if targetPlayer ~= player and not Game.onAfkTeam(targetPlayer) and not Game.sameTeam(targetPlayer) then local root = Game.aliveRoot(targetPlayer.Character) if root then local distance = (root.Position - ownRoot.Position).Magnitude if distance <= panel.range and (not bestDistance or distance < bestDistance) then best, bestDistance = targetPlayer, distance end end end end return best end local function refresh() local subject = nil if panel.enabled then subject = (farm.enabled and farm.targetPlayer) or nearestEnemy() end panel.subject = subject and subject.Name or nil local root, humanoid if subject then root, humanoid = Game.aliveRoot(subject.Character) end frame.Visible = root ~= nil if root then local ownRoot = Game.ownRoot() local distance = ownRoot and (root.Position - ownRoot.Position).Magnitude or 0 title.Text = subject.DisplayName title.TextColor3 = subject.Team and not Game.onAfkTeam(subject) and subject.TeamColor.Color or COLORS.text local tags = {tostring(Game.characterName(subject)), string.format("%dm", math.floor(distance + 0.5))} if Game.isBlocking(subject.Character) then tags[#tags + 1] = "BLOCKING" end local skill = Game.usingSkill(subject.Character) if skill then tags[#tags + 1] = "using " .. skill end subtitle.Text = table.concat(tags, " | ") local hp = math.clamp(humanoid.Health / math.max(humanoid.MaxHealth, 1), 0, 1) healthFill.Size = UDim2.fromScale(hp, 1) healthFill.BackgroundColor3 = healthColor(hp) healthText.Text = string.format("HP %d / %d", math.floor(humanoid.Health + 0.5), math.floor(humanoid.MaxHealth + 0.5)) local mode = Game.chargeFraction(subject) modeFill.Size = UDim2.fromScale(mode, 1) modeFill.BackgroundColor3 = mode >= 1 and COLORS.modeReady or COLORS.mode modeText.Text = mode >= 1 and "MODE READY" or string.format("mode %d%%", math.floor(mode * 100)) modeText.TextColor3 = mode >= 1 and COLORS.modeReady or COLORS.dim paintMoves(moveRows, Game.moves(subject)) end end task.spawn(function() while alive do local ok, reason = pcall(refresh) if not ok then warn("[Catn Hub panel] " .. tostring(reason)) end task.wait(0.1) end end) end local alerts = {enemies = false, own = false, enemiesOnly = true} state.Alerts = alerts do local wasFull = {} local function notify(title, content) pcall(function() BPUI:Notify({Title = title, Content = content, Type = "Warning", Duration = 4}) end) end task.spawn(function() while alive do for _, targetPlayer in ipairs(Players:GetPlayers()) do local fraction = Game.chargeFraction(targetPlayer) local full = fraction >= 1 if wasFull[targetPlayer] == nil then wasFull[targetPlayer] = full elseif wasFull[targetPlayer] and fraction < 0.9 then wasFull[targetPlayer] = false elseif full and not wasFull[targetPlayer] then wasFull[targetPlayer] = true if targetPlayer == player then if alerts.own then notify("Mode ready", "your mode bar is full") end elseif alerts.enemies and not Game.onAfkTeam(targetPlayer) and not (alerts.enemiesOnly and Game.sameTeam(targetPlayer)) then notify("Mode ready", targetPlayer.DisplayName .. " (" .. tostring(Game.characterName(targetPlayer)) .. ") has mode") end end end for targetPlayer in pairs(wasFull) do if targetPlayer.Parent ~= Players then wasFull[targetPlayer] = nil end end task.wait(0.5) end end) end local comp = { enabled = false, ring = true, reach = 9.5, ringOpacity = 0.55, strips = true, stripRange = 80, holdKey = Enum.KeyCode.LeftAlt, fpsSaver = false, accent = Color3.fromRGB(143, 112, 236), focus = nil, holding = false, } state.Comp = comp do local container = make("Folder", {Name = "BPHubComp"}, hiddenGuiParent()) onCleanup(function() container:Destroy() end) local YELLOW = Color3.fromRGB(255, 205, 70) local function enemyModel(model) if model == player.Character then return false end local owner = Players:GetPlayerFromCharacter(model) if not owner then return true, nil end return not Game.onAfkTeam(owner) and not Game.sameTeam(owner), owner end local ring = make("CylinderHandleAdornment", {Name = "Reach", Height = 0.06, Radius = comp.reach, InnerRadius = comp.reach - 0.18, ZIndex = 0, Visible = false, Color3 = COLORS.dim}, container) local live = workspace:FindFirstChild("Live") local stepTime = {} local tracked = setmetatable({}, {__mode = "k"}) local function learn(move, now) local value = move:GetAttribute("COOLDOWN") value = type(value) == "number" and value or 20 local seen = tracked[move] if not seen then tracked[move] = {value = value} return end if value > seen.value and value < 20 or (value == 20 and seen.value < 20) then if seen.at then local sample = (now - seen.at) / (value - seen.value) if sample > 0.05 and sample < 10 then local old = stepTime[move.Name] stepTime[move.Name] = old and (old * 0.7 + sample * 0.3) or sample end end seen.at = now elseif value < seen.value then seen.at = now end seen.value = value end local function short(name) local letters = {} for word in string.gmatch(name, "%w+") do letters[#letters + 1] = string.upper(string.sub(word, 1, 1)) end if #letters == 1 then return string.sub(name, 1, 2) end return #letters > 0 and (letters[1] .. letters[2]) or "?" end local CELLS, CELL = 5, 22 local strips = {} local function getStrip(targetPlayer) if strips[targetPlayer] then return strips[targetPlayer] end local billboard = make("BillboardGui", {AlwaysOnTop = true, Enabled = false, LightInfluence = 0, Size = UDim2.fromOffset(CELLS * (CELL + 2), CELL + 14), StudsOffset = Vector3.new(0, 3.6, 0), ResetOnSpawn = false}, container) local tags = makeText(billboard, {Size = UDim2.new(1, 0, 0, 12), Font = Enum.Font.GothamBold, TextSize = 11}) local row = make("Frame", {BackgroundTransparency = 1, Position = UDim2.fromOffset(0, 13), Size = UDim2.new(1, 0, 0, CELL)}, billboard) make("UIListLayout", {FillDirection = Enum.FillDirection.Horizontal, Padding = UDim.new(0, 2), HorizontalAlignment = Enum.HorizontalAlignment.Center}, row) local cells = {} for index = 1, CELLS do local cell = make("Frame", {BackgroundColor3 = COLORS.barBack, BackgroundTransparency = 0.2, BorderSizePixel = 0, Size = UDim2.fromOffset(CELL, CELL), LayoutOrder = index, Visible = false}, row) make("UICorner", {CornerRadius = UDim.new(0, 4)}, cell) local fill = make("Frame", {AnchorPoint = Vector2.new(0, 1), Position = UDim2.fromScale(0, 1), BorderSizePixel = 0, BackgroundTransparency = 0.35, Size = UDim2.fromScale(1, 1)}, cell) make("UICorner", {CornerRadius = UDim.new(0, 4)}, fill) local label = makeText(cell, {Size = UDim2.fromScale(1, 1), Font = Enum.Font.GothamBold, TextSize = 11, TextStrokeTransparency = 0.2, ZIndex = 2}) cells[index] = {cell = cell, fill = fill, label = label} end strips[targetPlayer] = {billboard = billboard, tags = tags, cells = cells} return strips[targetPlayer] end connect(Players.PlayerRemoving, function(targetPlayer) if strips[targetPlayer] then strips[targetPlayer].billboard:Destroy() strips[targetPlayer] = nil end end) local function paintStrip(strip, targetPlayer, character) local moves = Game.moves(targetPlayer) local backpack = targetPlayer:FindFirstChildOfClass("Backpack") for index, cell in ipairs(strip.cells) do local move = moves[index] cell.cell.Visible = move ~= nil if move then cell.fill.Size = UDim2.fromScale(1, move.progress) cell.fill.BackgroundColor3 = move.ready and comp.accent or COLORS.charging local text = short(move.name) local step = stepTime[move.name] if not move.ready and step then local config = backpack and backpack:FindFirstChild(move.name) local value = config and config:GetAttribute("COOLDOWN") if type(value) == "number" then text = tostring(math.ceil((20 - value) * step)) end end cell.label.Text = text cell.label.TextColor3 = move.ready and COLORS.text or COLORS.dim end end local tags = {} if Game.isBlocking(character) then tags[#tags + 1] = "BLOCK" end if character:FindFirstChild("Counter") then tags[#tags + 1] = "COUNTER" end if Game.chargeFraction(targetPlayer) >= 1 then tags[#tags + 1] = "MODE" end strip.tags.Text = table.concat(tags, " ") strip.tags.TextColor3 = #tags > 0 and YELLOW or COLORS.text strip.billboard.Adornee = character:FindFirstChild("Head") or character:FindFirstChild("HumanoidRootPart") strip.billboard.Enabled = true end local function pickFocus(mine) local camera = workspace.CurrentCamera if not camera then return nil end local look = camera.CFrame.LookVector local best, bestAngle, near, nearDistance for _, targetPlayer in ipairs(Players:GetPlayers()) do if targetPlayer ~= player and not Game.onAfkTeam(targetPlayer) and not Game.sameTeam(targetPlayer) then local root = Game.aliveRoot(targetPlayer.Character) if root then local distance = (root.Position - mine.Position).Magnitude if distance <= comp.stripRange then local offset = root.Position - camera.CFrame.Position local angle = math.deg(math.acos(math.clamp(look:Dot(offset.Unit), -1, 1))) if angle < 20 and (not bestAngle or angle < bestAngle) then best, bestAngle = targetPlayer, angle end if distance < 20 and (not nearDistance or distance < nearDistance) then near, nearDistance = targetPlayer, distance end end end end end return best or near end connect(UIS.InputBegan, function(input) if input.KeyCode == comp.holdKey and comp.holdKey ~= Enum.KeyCode.Unknown then comp.holding = true end end) connect(UIS.InputEnded, function(input) if input.KeyCode == comp.holdKey then comp.holding = false end end) local tick = 0 local function update() local now = os.clock() local mine, humanoid = Game.ownRoot() local on = comp.enabled and alive local showRing = on and comp.ring and not comp.fpsSaver and mine ~= nil ring.Visible = showRing if showRing then if ring.Adornee ~= mine then ring.Adornee = mine end local drop = humanoid.HipHeight + mine.Size.Y / 2 - 0.08 ring.CFrame = CFrame.new(0, -drop, 0) * CFrame.Angles(math.rad(90), 0, 0) ring.Radius, ring.InnerRadius = comp.reach, math.max(0, comp.reach - 0.18) local inRange = false if live then for _, model in ipairs(live:GetChildren()) do local root = model:FindFirstChild("HumanoidRootPart") if root and (root.Position - mine.Position).Magnitude <= comp.reach and enemyModel(model) then local _, other = Game.aliveRoot(model) if other then inRange = true break end end end end ring.Color3 = inRange and comp.accent or COLORS.dim ring.Transparency = inRange and math.max(0, 1 - comp.ringOpacity - 0.25) or 1 - comp.ringOpacity end tick = tick + 1 if tick % 2 ~= 0 then return end for _, targetPlayer in ipairs(Players:GetPlayers()) do local backpack = targetPlayer:FindFirstChildOfClass("Backpack") if backpack then for _, move in ipairs(backpack:GetChildren()) do if move:IsA("Configuration") then learn(move, now) end end end end if not on or not mine then for _, strip in pairs(strips) do strip.billboard.Enabled = false end comp.focus = nil return end local focus = pickFocus(mine) comp.focus = focus and focus.Name or nil local showStrips = comp.strips and not comp.fpsSaver for _, targetPlayer in ipairs(Players:GetPlayers()) do if targetPlayer ~= player then local character = targetPlayer.Character local root = Game.aliveRoot(character) local enemy = root and not Game.onAfkTeam(targetPlayer) and not Game.sameTeam(targetPlayer) local distance = root and (root.Position - mine.Position).Magnitude or math.huge local shown = showStrips and enemy and distance <= comp.stripRange and (targetPlayer == focus or comp.holding) if shown then paintStrip(getStrip(targetPlayer), targetPlayer, character) elseif strips[targetPlayer] then strips[targetPlayer].billboard.Enabled = false end end end if comp.preview and player.Character then paintStrip(getStrip(player), player, player.Character) elseif strips[player] then strips[player].billboard.Enabled = false end end task.spawn(function() while alive do local ok, reason = pcall(update) if not ok then warn("[Catn Hub comp] " .. tostring(reason)) end task.wait(0.05) end ring.Visible = false end) end local session = {started = os.clock(), gold = 0, kills = 0, deaths = 0, damage = 0} state.Session = session do local function track(valueObject, key) if not valueObject or not valueObject:IsA("ValueBase") then return end local last = tonumber(valueObject.Value) or 0 connect(valueObject.Changed, function(value) value = tonumber(value) or 0 if value > last then session[key] = session[key] + (value - last) end last = value end) end task.spawn(function() local stats = player:WaitForChild("Stats", 15) if alive and stats then track(stats:FindFirstChild("Kills"), "kills") track(stats:FindFirstChild("Deaths"), "deaths") track(stats:FindFirstChild("Damage"), "damage") end local replicated = player:WaitForChild("ReplicatedStats", 15) if alive and replicated then track(replicated:FindFirstChild("Gold"), "gold") end end) session.Reset = function() session.started, session.gold, session.kills, session.deaths, session.damage = os.clock(), 0, 0, 0, 0 end end local misc = {antiAfk = false, autoTab = true} state.Misc = misc connect(player.Idled, function() if not misc.antiAfk then return end pcall(function() local virtualUser = game:GetService("VirtualUser") virtualUser:CaptureController() virtualUser:ClickButton2(Vector2.new()) end) end) local created, result = pcall(function() return BPUI:CreateWindow({Version = "1.3.1", Title = "Catn Hub", Subtitle = "Anime Battle Arena", Icon = "zap", Theme = "Void", Accent = Color3.fromRGB(143, 112, 236), ToggleKey = Enum.KeyCode.RightShift, ShowSettings = true, ConfigFolder = "BPHubABA", Watermark = false, CloseBehavior = "Hide", OnDestroy = cleanup, }) end) if not created then cleanup() error("Window creation failed: " .. tostring(result)) end window = result local ui = {} local toggles = {} local function addToggle(section, config) local element = section:AddToggle(config) if config.Panic ~= false then toggles[#toggles + 1] = element end return element end local function teamDropdown(section, flag, onChange) return section:AddDropdown({Name = "Team check", Options = Game.teamModeOptions, Default = "Enemies only", Flag = flag, Callback = function(value) onChange(Game.teamModes[value] or "enemies") end}) end local overviewTab = window:CreateTab({Name = "Overview", Icon = "home"}) do local info = overviewTab:CreateSection("Info") ui.status = info:AddLabel({Text = supported and "ABA detected" or "Wrong game, features locked", Style = supported and "Success" or "Error"}) ui.character = info:AddLabel({Text = "Character: -", Style = "Sub"}) ui.performance = info:AddLabel({Text = "FPS: - | ping: -", Style = "Sub"}) ui.selfCheck = info:AddLabel({Text = "self check: running...", Style = "Sub"}) info:AddButton({Name = "Unload", Callback = function() state.Destroy() end}) local sessionSection = overviewTab:CreateSection("Session") ui.sessionTime = sessionSection:AddLabel({Text = "time: 0m", Style = "Sub"}) ui.sessionGold = sessionSection:AddLabel({Text = "gold: +0", Style = "Sub"}) ui.sessionFights = sessionSection:AddLabel({Text = "kills: 0 | deaths: 0 | damage: 0", Style = "Sub"}) sessionSection:AddButton({Name = "Reset session", Callback = session.Reset}) local statusSection = overviewTab:CreateSection("Status") ui.overview = {} for _, key in ipairs({"farm", "esp", "panel", "anyBlackFlash", "yuji", "nanami", "yusuke", "krillin"}) do ui.overview[key] = statusSection:AddLabel({Text = "-", Style = "Sub"}) end local keys = overviewTab:CreateSection("Default keys") for _, line in ipairs({ "RightShift open/close menu", "End turn everything off", "F2 auto block", "F3 Black Flash (any character)", "F4 ESP", "F5 target panel", "F6 Nanami auto hit", "F7 Yusuke gun sweep", "F8 / F9 Yuji Black Flash / Divergent", "F10 Krillin kiblast", "F11 Auto Farm", "Insert Comp HUD", }) do keys:AddLabel({Text = line, Style = "Sub"}) end end local farmTab = window:CreateTab({Name = "Auto Farm", Icon = "crosshair"}) do local farmInputs = canKeyClick or (click ~= nil and canAimMouse) local control = farmTab:CreateSection("Auto Farm") local farmToggle = addToggle(control, {Name = "Auto Farm", Default = false, Description = "Teleports to your target and spams your moves.", Callback = function(value) farm.SetEnabled(value) end}) if not farmInputs then farmToggle:Lock() end control:AddKeybind({Name = "Keybind", Default = Enum.KeyCode.F11, Mode = "Press", Flag = "farm_key", Callback = function() if alive and farmInputs then farmToggle:Set(not farm.enabled) end end}) ui.farmStatus = control:AddLabel({Text = "off", Style = "Sub"}) ui.farmTarget = control:AddLabel({Text = "target: none", Style = "Sub"}) local targets = farmTab:CreateSection("Targets") teamDropdown(targets, "farm_team", function(mode) farm.teamMode = mode farm.Retarget() end) targets:AddToggle({Name = "Skip AFK team", Default = true, Flag = "farm_skip_afk", Callback = function(value) farm.skipAfk = value == true farm.Retarget() end}) targets:AddDropdown({Name = "Priority", Options = farm.priorityOptions, Default = "Nearest", Flag = "farm_priority", Description = "Most damage goes after whoever has dealt the most this match.", Callback = function(value) farm.priority = value farm.Retarget() end}) targets:AddToggle({Name = "Avoid blocking players", Default = true, Flag = "farm_avoid_blocking", Description = "Picks someone who isn't blocking when it can.", Callback = function(value) farm.avoidBlocking = value == true end}) targets:AddToggle({Name = "Avoid players with mode ready", Default = false, Flag = "farm_avoid_mode", Description = "Picks someone without a full mode bar when it can.", Callback = function(value) farm.avoidModeReady = value == true end}) targets:AddSlider({Name = "Max range", Min = 0, Max = 2000, Default = 0, Increment = 25, Suffix = " studs", Flag = "farm_max_range", Description = "0 = any distance.", Callback = function(value) farm.maxRange = math.max(0, tonumber(value) or 0) farm.Retarget() end}) targets:AddToggle({Name = "Stay on target until it dies", Default = true, Flag = "farm_stay_on_target", Description = "Off = switches to a better target every second.", Callback = function(value) farm.stayOnTarget = value == true end}) ui.farmPreview = targets:AddLabel({Text = "would pick: -", Style = "Sub"}) local position = farmTab:CreateSection("Position") position:AddDropdown({Name = "Stand position", Options = farm.positionOptions, Default = "Behind", Flag = "farm_position", Description = "Behind is safest.", Callback = function(value) farm.position = value end}) position:AddSlider({Name = "Distance", Min = 1, Max = 12, Default = 3, Increment = 0.5, Suffix = " studs", Flag = "farm_distance", Callback = function(value) farm.standoff = math.clamp(tonumber(value) or 3, 1, 12) end}) position:AddToggle({Name = "Stick to target", Default = true, Flag = "farm_sticky", Callback = function(value) farm.sticky = value == true end}) position:AddToggle({Name = "Aim camera at target", Default = true, Flag = "farm_aim", Callback = function(value) farm.aimCamera = value == true end}) local attacks = farmTab:CreateSection("Attacks") attacks:AddToggle({Name = "Only use ready moves", Default = true, Flag = "farm_only_ready", Description = "Skips moves that are still on cooldown.", Callback = function(value) farm.onlyReady = value == true end}) for index = 1, 4 do local key = tostring(index) local moveToggle = attacks:AddToggle({Name = "Use move " .. key, Default = canKeyClick, Flag = "farm_move" .. key, Callback = function(value) farm.attacks[key] = value == true end}) if not canKeyClick then moveToggle:Lock() end end local m1Toggle = attacks:AddToggle({Name = "Use M1", Default = click ~= nil and canAimMouse, Flag = "farm_m1", Callback = function(value) farm.attacks.M1 = value == true end}) if not (click and canAimMouse) then m1Toggle:Lock() end attacks:AddToggle({Name = "Auto mode (G)", Default = false, Flag = "farm_mode", Description = "Doesn't activate mode yet, the server ignores it.", Callback = function(value) farm.attacks.Mode = value == true end}) ui.modeBar = attacks:AddLabel({Text = "mode bar: -", Style = "Sub"}) end local defenseTab = window:CreateTab({Name = "Defense", Icon = "shield"}) do local section = defenseTab:CreateSection("Auto block") local blockToggle = addToggle(section, {Name = "Auto block", Default = false, Flag = "auto_block", Description = "Blocks when a nearby enemy starts an attack. Works with Roblox in the background.", Callback = function(value) autoBlock.SetEnabled(value) end}) section:AddKeybind({Name = "Keybind", Default = Enum.KeyCode.F2, Mode = "Press", Flag = "auto_block_key", Callback = function() if alive then blockToggle:Set(not autoBlock.enabled) end end}) ui.autoBlock = section:AddLabel({Text = "off", Style = "Sub"}) local tuning = defenseTab:CreateSection("Tuning") tuning:AddSlider({Name = "Range", Min = 6, Max = 30, Default = 14, Increment = 1, Suffix = " studs", Flag = "auto_block_range", Description = "How close an enemy's attack has to start. Moves count from twice as far.", Callback = function(value) autoBlock.range = tonumber(value) or 14 end}) tuning:AddSlider({Name = "Hold", Min = 0.2, Max = 1, Default = 0.45, Increment = 0.05, Suffix = " s", Flag = "auto_block_hold", Description = "How long block stays up after each attack starts.", Callback = function(value) autoBlock.hold = tonumber(value) or 0.45 end}) tuning:AddToggle({Name = "Skip guardbreak moves", Default = true, Flag = "auto_block_skip_gb", Description = "Moves that go through block aren't worth blocking.", Callback = function(value) autoBlock.skipGuardbreaks = value == true end}) tuning:AddToggle({Name = "Keep blocking while auto farm runs", Default = false, Flag = "auto_block_farm", Description = "Off: auto block waits while the farm is on, so it doesn't cut your attacks short.", Callback = function(value) autoBlock.whileFarming = value == true end}) tuning:AddLabel({Text = "the 5th hit of an M1 chain knocks block off for a few seconds; nothing gets around that", Style = "Sub"}) end local visualsTab = window:CreateTab({Name = "Visuals", Icon = "eye"}) do local espSection = visualsTab:CreateSection("ESP") local espToggle = addToggle(espSection, {Name = "Enabled", Default = false, Flag = "esp_enabled", Callback = function(value) esp.enabled = value == true and alive end}) espSection:AddKeybind({Name = "Keybind", Default = Enum.KeyCode.F4, Mode = "Press", Flag = "esp_key", Callback = function() if alive then espToggle:Set(not esp.enabled) end end}) ui.espStatus = espSection:AddLabel({Text = "off", Style = "Sub"}) local show = visualsTab:CreateSection("Show") for _, option in ipairs({ {"outline", "Outline"}, {"fill", "Fill"}, {"labels", "Name"}, {"distance", "Distance"}, {"healthBar", "Health bar"}, {"modeBar", "Mode bar"}, {"cooldowns", "Move cooldowns"}, }) do local key = option[1] show:AddToggle({Name = option[2], Default = true, Flag = "esp_" .. key, Callback = function(value) esp[key] = value == true end}) end show:AddLabel({Text = "cooldowns: green = ready, orange = charging", Style = "Sub"}) show:AddLabel({Text = "mode: purple = charging, gold = ready", Style = "Sub"}) local filters = visualsTab:CreateSection("Filters") filters:AddToggle({Name = "Hide teammates", Default = true, Flag = "esp_hide_team", Callback = function(value) esp.hideTeammates = value == true end}) filters:AddToggle({Name = "Hide AFK", Default = true, Flag = "esp_hide_afk", Callback = function(value) esp.hideAfk = value == true end}) filters:AddToggle({Name = "Limit distance", Default = false, Flag = "esp_limit_distance", Callback = function(value) esp.limitDistance = value == true end}) filters:AddSlider({Name = "Max distance", Min = 100, Max = 5000, Default = 1500, Increment = 50, Suffix = " studs", Flag = "esp_max_distance", Callback = function(value) esp.maxDistance = tonumber(value) or 1500 end}) local colors = visualsTab:CreateSection("Colors") colors:AddToggle({Name = "Team colors", Default = true, Flag = "esp_team_colors", Callback = function(value) esp.teamColors = value == true end}) colors:AddColorPicker({Name = "Enemy", Default = esp.enemyColor, Flag = "esp_enemy_color", Callback = function(value) esp.enemyColor = value end}) colors:AddColorPicker({Name = "Teammate", Default = esp.allyColor, Flag = "esp_ally_color", Callback = function(value) esp.allyColor = value end}) local panelSection = visualsTab:CreateSection("Target panel") local panelToggle = addToggle(panelSection, {Name = "Target panel", Default = false, Flag = "panel_enabled", Description = "Card with your target's HP, mode and cooldowns. Drag it to move it.", Callback = function(value) panel.enabled = value == true and alive end}) panelSection:AddKeybind({Name = "Keybind", Default = Enum.KeyCode.F5, Mode = "Press", Flag = "panel_key", Callback = function() if alive then panelToggle:Set(not panel.enabled) end end}) panelSection:AddSlider({Name = "Range", Min = 25, Max = 1000, Default = 150, Increment = 25, Suffix = " studs", Flag = "panel_range", Description = "How close an enemy has to be when you're not farming.", Callback = function(value) panel.range = tonumber(value) or 150 end}) local alertSection = visualsTab:CreateSection("Mode alerts") addToggle(alertSection, {Name = "Enemy mode ready", Default = false, Flag = "alert_enemies", Callback = function(value) alerts.enemies = value == true end}) alertSection:AddToggle({Name = "Only enemies", Default = true, Flag = "alert_enemies_only", Callback = function(value) alerts.enemiesOnly = value == true end}) addToggle(alertSection, {Name = "My mode ready", Default = false, Flag = "alert_own", Callback = function(value) alerts.own = value == true end}) end local compTab = window:CreateTab({Name = "Comp", Icon = "trophy"}) do local hud = compTab:CreateSection("Comp HUD") local compToggle = addToggle(hud, {Name = "Comp HUD", Default = false, Flag = "comp_enabled", Description = "Reach ring and enemy cooldowns. Only shows what the game already sends you.", Callback = function(value) comp.enabled = value == true and alive end}) hud:AddKeybind({Name = "Keybind", Default = Enum.KeyCode.Insert, Mode = "Press", Flag = "comp_key", Callback = function() if alive then compToggle:Set(not comp.enabled) end end}) hud:AddToggle({Name = "FPS saver", Default = false, Flag = "comp_fps_saver", Description = "Hides the ring and strips without turning the HUD off.", Callback = function(value) comp.fpsSaver = value == true end}) ui.compStatus = hud:AddLabel({Text = "off", Style = "Sub"}) local ringSection = compTab:CreateSection("Reach ring") ringSection:AddToggle({Name = "Ring", Default = true, Flag = "comp_ring", Description = "Lights up when an enemy is inside your M1 reach.", Callback = function(value) comp.ring = value == true end}) ringSection:AddSlider({Name = "M1 reach", Min = 6, Max = 14, Default = 9.5, Increment = 0.1, Suffix = " studs", Flag = "comp_reach", Description = "Measured: lands at 9.8, misses at 10. 9.5 leaves room for ping.", Callback = function(value) comp.reach = tonumber(value) or 9.5 end}) ringSection:AddSlider({Name = "Opacity", Min = 0.1, Max = 1, Default = 0.55, Increment = 0.05, Flag = "comp_ring_opacity", Callback = function(value) comp.ringOpacity = tonumber(value) or 0.55 end}) local cds = compTab:CreateSection("Cooldown strips") cds:AddToggle({Name = "Focus target strip", Default = true, Flag = "comp_strips", Description = "Over the enemy you're looking at: one cell per move, seconds left once learned.", Callback = function(value) comp.strips = value == true end}) local holdKeys = {["Left Alt"] = Enum.KeyCode.LeftAlt, Tab = Enum.KeyCode.Tab, ["Caps Lock"] = Enum.KeyCode.CapsLock, ["Left Ctrl"] = Enum.KeyCode.LeftControl, None = Enum.KeyCode.Unknown} cds:AddDropdown({Name = "Show all while holding", Options = {"Left Alt", "Tab", "Caps Lock", "Left Ctrl", "None"}, Default = "Left Alt", Flag = "comp_hold_key", Callback = function(value) comp.holdKey = holdKeys[value] or Enum.KeyCode.LeftAlt comp.holding = false end}) cds:AddSlider({Name = "Range", Min = 20, Max = 300, Default = 80, Increment = 10, Suffix = " studs", Flag = "comp_strip_range", Callback = function(value) comp.stripRange = tonumber(value) or 80 end}) cds:AddColorPicker({Name = "Accent", Default = comp.accent, Flag = "comp_accent", Callback = function(value) comp.accent = value end}) cds:AddLabel({Text = "seconds show after a move has ticked once; before that, its initials", Style = "Sub"}) end local playerInfoTab = window:CreateTab({Name = "Player Info", Icon = "users"}) local playerInfoSection = playerInfoTab:CreateSection("Players") ui.playerCount = playerInfoSection:AddLabel({Text = "loading...", Style = "Sub"}) local playerCards = {} local function playerCardText(targetPlayer) local title = targetPlayer.DisplayName .. " (" .. tostring(Game.characterName(targetPlayer)) .. ")" local mode = math.floor(Game.chargeFraction(targetPlayer) * 100 + 0.5) local lines = {string.format("%s | %d kills, %d deaths | %d dmg | mode %s", targetPlayer.Team and targetPlayer.Team.Name or "no team", Game.stat(targetPlayer, "Kills"), Game.stat(targetPlayer, "Deaths"), math.floor(Game.stat(targetPlayer, "Damage") + 0.5), mode >= 100 and "READY" or (mode .. "%"))} local skill = Game.usingSkill(targetPlayer.Character) if skill then lines[#lines + 1] = "using: " .. skill end for _, move in ipairs(Game.moves(targetPlayer)) do lines[#lines + 1] = move.name .. ": " .. (move.ready and "ready" or (math.floor(move.progress * 100) .. "%")) end return title, table.concat(lines, "\n") end local function refreshPlayerInfo() local list = Players:GetPlayers() for _, targetPlayer in ipairs(list) do local card = playerCards[targetPlayer] if not card then card = playerInfoSection:AddParagraph({Title = targetPlayer.Name, Content = ""}) playerCards[targetPlayer] = card end local title, content = playerCardText(targetPlayer) card:SetTitle(title) card:SetContent(content) end for targetPlayer, card in pairs(playerCards) do if targetPlayer.Parent ~= Players then card:Destroy() playerCards[targetPlayer] = nil end end ui.playerCount:Set(#list .. " players") end local charactersGroup = window:CreateGroup({Name = "Characters", Icon = "users", Open = false}) local characterTabs = {} characterTabs.Any = charactersGroup:CreateTab({Name = "Any character", Icon = "zap"}) characterTabs.Yuji = charactersGroup:CreateTab({Name = "Yuji", Icon = "zap"}) characterTabs.Yusuke = charactersGroup:CreateTab({Name = "Yusuke", Icon = "crosshair"}) characterTabs.Krillin = charactersGroup:CreateTab({Name = "Krillin", Icon = "target"}) characterTabs.Nanami = charactersGroup:CreateTab({Name = "Nanami", Icon = "zap"}) characterTabs.Kokushibo = charactersGroup:CreateTab({Name = "Kokushibo", Icon = "zap"}) local function assistControls(section, config) local element = addToggle(section, {Name = config.name, Default = config.default, Flag = config.flag, Description = config.description, Callback = config.callback}) if config.locked then element:Lock() end section:AddKeybind({Name = "Keybind", Default = config.key, Mode = "Press", Flag = config.flag .. "_key", Callback = function() if alive and not config.locked then element:Set(not config.get()) end end}) return section:AddLabel({Text = "-", Style = "Sub"}) end do local section = characterTabs.Any:CreateSection("Black Flash (any character)") ui.anyBlackFlash = assistControls(section, {name = "Auto Black Flash", default = anyBlackFlash.enabled, flag = "any_black_flash", key = Enum.KeyCode.F3, locked = not supported, description = "Clicks the zoom-in Black Flash check for whoever you're playing.", get = function() return anyBlackFlash.enabled end, callback = function(value) anyBlackFlash.enabled = value == true and supported and alive anyBlackFlash.last = anyBlackFlash.enabled and "waiting" or "off" end}) section:AddLabel({Text = "if Yuji's own Black Flash misfires with this on, turn one off", Style = "Sub"}) end do local blackFlash = characterTabs.Yuji:CreateSection("Black Flash (move 2)") ui.yujiBlackFlash = assistControls(blackFlash, {name = "Auto Black Flash", default = yuji.blackFlash, flag = "yuji_black_flash", key = Enum.KeyCode.F8, locked = not supported, description = "Clicks for you when the Black Flash cue hits.", get = function() return yuji.blackFlash end, callback = function(value) yuji.blackFlash = value == true and supported and alive yuji.blackFlashLast = yuji.blackFlash and "waiting for move 2" or "off" end}) local divergent = characterTabs.Yuji:CreateSection("Divergent Fist (move 1)") ui.yujiDivergent = assistControls(divergent, {name = "Auto Divergent", default = yuji.divergent, flag = "yuji_divergent", key = Enum.KeyCode.F9, locked = not supported, description = "Works after you land a Black Flash.", get = function() return yuji.divergent end, callback = function(value) yuji.divergent = value == true and supported and alive yuji.divergentLast = yuji.divergent and "waiting for move 1" or "off" end}) local skull = characterTabs.Yuji:CreateSection("Skull Smash (move 4)") local skullToggle = addToggle(skull, {Name = "Auto Skull Smash", Default = false, Flag = "yuji_skull", Description = "Clicks about 1.5s into the move. Timing can be off.", Callback = function(value) yuji.skull = value == true and supported and alive yuji.skullLast = yuji.skull and "waiting for move 4" or "off" end}) if not supported then skullToggle:Lock() end ui.yujiSkull = skull:AddLabel({Text = "-", Style = "Sub"}) end do local section = characterTabs.Nanami:CreateSection("Ratio / 7:3 Black Flash") ui.nanami = assistControls(section, {name = "Auto hit", default = nanami.enabled, flag = "nanami_hit", key = Enum.KeyCode.F6, locked = not supported, description = "Hits the timing bar on move 1 and the second 7:3.", get = function() return nanami.enabled end, callback = function(value) nanami.enabled = value == true and supported and alive nanami.last = nanami.enabled and "waiting" or "off" end}) end do local section = characterTabs.Kokushibo:CreateSection("Timed right click") ui.kokushibo = assistControls(section, {name = "Auto right click", default = false, flag = "kokushibo_check", key = Enum.KeyCode.F12, locked = not kokushibo.available, description = "Presses during the check's window at a different moment each time, so the game's same-timing kick never sees a pattern.", get = function() return kokushibo.enabled end, callback = function(value) kokushibo.enabled = value == true and kokushibo.available and alive kokushibo.last = kokushibo.enabled and "waiting" or "off" end}) section:AddLabel({Text = "works with roblox in the background too", Style = "Sub"}) end do local section = characterTabs.Yusuke:CreateSection("Spirit Gun / Demon Gun") ui.yusuke = assistControls(section, {name = "Gun sweep", default = yusuke.enabled, flag = "yusuke_sweep", key = Enum.KeyCode.F7, locked = not yusuke.available, description = "Bounces your Spirit Gun / Demon Gun shot through every nearby target.", get = function() return yusuke.enabled end, callback = function(value) yusuke.enabled = value == true and yusuke.available and alive end}) teamDropdown(section, "yusuke_team", function(mode) yusuke.teamMode = mode end) end do local section = characterTabs.Krillin:CreateSection("Kiblast") ui.krillin = assistControls(section, {name = "Redirect kiblasts", default = krillin.enabled, flag = "krillin_redirect", key = Enum.KeyCode.F10, locked = not correctGame, description = "Sends each volley at one random player.", get = function() return krillin.enabled end, callback = function(value) krillin.enabled = value == true and correctGame and alive krillin.last = krillin.enabled and "waiting for kiblast" or "off" end}) local targets = characterTabs.Krillin:CreateSection("Targets") teamDropdown(targets, "krillin_team", function(mode) krillin.teamMode = mode end) targets:AddToggle({Name = "Hit anyone if no enemies", Default = false, Flag = "krillin_fallback", Callback = function(value) krillin.fallback = value == true end}) local timingSection = characterTabs.Krillin:CreateSection("Timing") timingSection:AddSlider({Name = "Volley gap", Min = 0.1, Max = 1, Default = 0.35, Increment = 0.05, Suffix = " s", Flag = "krillin_gap", Callback = function(value) krillin.volleyGap = tonumber(value) or 0.35 end}) timingSection:AddSlider({Name = "Hold per part", Min = 0.1, Max = 0.8, Default = 0.4, Increment = 0.05, Suffix = " s", Flag = "krillin_hold", Callback = function(value) krillin.holdTime = tonumber(value) or 0.4 end}) end local miscTab = window:CreateTab({Name = "Misc", Icon = "settings"}) do local general = miscTab:CreateSection("General") general:AddToggle({Name = "Anti-AFK", Default = false, Flag = "misc_anti_afk", Description = "Stops the Roblox idle kick.", Callback = function(value) misc.antiAfk = value == true end}) general:AddToggle({Name = "Open my character's tab on spawn", Default = true, Flag = "misc_auto_tab", Callback = function(value) misc.autoTab = value == true end}) general:AddKeybind({Name = "Turn everything off", Default = Enum.KeyCode.End, Mode = "Press", Flag = "misc_panic_key", Callback = function() for _, element in ipairs(toggles) do pcall(function() element:Set(false) end) end pcall(function() BPUI:Notify({Title = "Catn Hub", Content = "everything off", Duration = 2}) end) end}) local server = miscTab:CreateSection("Server") server:AddLabel({Text = "job id: " .. (game.JobId ~= "" and game.JobId or "studio"), Style = "Sub"}) server:AddButton({Name = "Rejoin this server", Callback = function() pcall(function() TeleportService:TeleportToPlaceInstance(game.PlaceId, game.JobId, player) end) end}) server:AddToggle({Name = "Rejoin if kicked or disconnected", Default = false, Flag = "auto_rejoin", Description = "Joins ABA again when Roblox shows a kick or disconnect message.", Callback = function(value) rejoin.enabled = value == true rejoin.last = rejoin.enabled and "watching" or "off" end}) server:AddInput({Name = "Run after rejoining", Placeholder = "your loadstring line", Flag = "auto_rejoin_loader", Description = "Paste the line you use to load the hub and it starts again in the new server.", Callback = function(text) rejoin.loader = tostring(text or "") end}) ui.rejoin = server:AddLabel({Text = "off", Style = "Sub"}) if type(queue_on_teleport) ~= "function" then server:AddLabel({Text = "this executor can't run things after a teleport, so only the rejoin works", Style = "Sub"}) end local replicated = game:GetService("ReplicatedStorage") local function find(root, ...) local node = root for _, name in ipairs({...}) do node = node and node:FindFirstChild(name) end return node end local checks = { {"ABA place", "everything", function() return correctGame end}, {"mouse1click", "click assists, M1", function() return click ~= nil end}, {"keyclick", "Auto Farm moves", function() return canKeyClick end}, {"mousemoveabs", "Auto Farm M1 aim", function() return canAimMouse end}, {"isnetworkowner", "Yusuke sweep", function() return canCheckOwner end}, {"gethui", "hiding ESP / panel", function() return type(gethui) == "function" end, true}, {"NanamiCutGUI bar", "Nanami auto hit", function() return find(replicated, "NanamiCutGUI", "MainBar", "Cutter") ~= nil end}, {"NanamiCheck", "Nanami auto hit", function() return replicated:FindFirstChild("NanamiCheck") ~= nil end}, {"BlackFlashCheck", "Black Flash (any)", function() return replicated:FindFirstChild("BlackFlashCheck") ~= nil end}, {"KokushiboCheck", "Kokushibo right click", function() return kokushibo.available end}, {"Player.Charge", "mode bars, alerts", function() local charge = player:FindFirstChild("Charge") return charge ~= nil and (pcall(function() return charge.MaxValue end)) end}, {"Player.Stats", "session, Player Info", function() return find(player, "Stats", "Kills") ~= nil and find(player, "Stats", "Damage") ~= nil end}, {"ReplicatedStats.Gold", "session gold", function() return find(player, "ReplicatedStats", "Gold") ~= nil end}, {"move cooldowns", "cooldown bars, ready moves", function() for _, targetPlayer in ipairs(Players:GetPlayers()) do local backpack = targetPlayer:FindFirstChildOfClass("Backpack") if backpack and backpack:FindFirstChildOfClass("Configuration") then return true end end return false end, true}, {"workspace.Live", "Yusuke sweep", function() return workspace:FindFirstChild("Live") ~= nil end}, {"workspace.Thrown", "Yusuke sweep", function() return workspace:FindFirstChild("Thrown") ~= nil end, true}, {".AFK team", "AFK filters", function() for _, team in ipairs(game:GetService("Teams"):GetTeams()) do if string.find(string.lower(team.Name), "afk", 1, true) then return true end end return false end, true}, {"UseMode action", "Auto mode (G)", function() return find(player, "PlayerScripts", "BaseContext", "UseMode") ~= nil end, true}, } local checkSection = miscTab:CreateSection("Self check") checkSection:AddLabel({Text = executor, Style = "Sub"}) local summary = checkSection:AddLabel({Text = "checking...", Style = "Sub"}) local rows = {} for index, check in ipairs(checks) do rows[index] = checkSection:AddLabel({Text = check[1], Style = "Sub"}) end local function runChecks() local missing, unsure = {}, 0 for index, check in ipairs(checks) do local okCall, passed = pcall(check[3]) passed = okCall and passed == true if passed then rows[index]:Set("ok " .. check[1]) elseif check[4] then unsure = unsure + 1 rows[index]:Set("not found " .. check[1] .. " (" .. check[2] .. ", can be normal outside a match)") else missing[#missing + 1] = check[2] rows[index]:Set("MISSING " .. check[1] .. " -> " .. check[2] .. " won't work") end end local text = #missing == 0 and ("all good" .. (unsure > 0 and (", " .. unsure .. " not found yet") or "")) or (#missing .. " missing: " .. table.concat(missing, ", ")) summary:Set(text) ui.selfCheck:Set("self check: " .. text) state.selfCheck = text return #missing end state.RunSelfCheck = runChecks checkSection:AddButton({Name = "Run again", Callback = runChecks}) task.spawn(function() task.wait(3) if not alive then return end local missingCount = runChecks() if missingCount > 0 then pcall(function() BPUI:Notify({Title = "Catn Hub", Content = "self check: " .. missingCount .. " missing, see Misc", Type = "Warning", Duration = 5}) end) end while alive do task.wait(30) if alive then pcall(runChecks) end end end) end do local tabFor = {Yuji = characterTabs.Yuji, Yusuke = characterTabs.Yusuke, Krillin = characterTabs.Krillin, Nanami = characterTabs.Nanami} local function openTab(character) task.wait(1.5) if not alive or not misc.autoTab or player.Character ~= character then return end local loadedName = character:GetAttribute("LastLoadedChar") if type(loadedName) ~= "string" then return end for key, tab in pairs(tabFor) do if string.find(loadedName, key, 1, true) then pcall(function() tab:Select() end) return end end end connect(player.CharacterAdded, function(character) task.spawn(openTab, character) end) end if player.Character then bindYuji(player.Character) end connect(player.CharacterAdded, bindYuji) window:SelectTab("Overview") pcall(function() window:Notify({Title = "Catn Hub", Content = supported and "loaded, RightShift to open" or "loaded, but this isn't ABA", Type = supported and "Success" or "Warning", Duration = 4}) end) local function tabOpen(tab) local ok, open = pcall(function() return window._visible ~= false and window._activeTab == tab end) return not ok or open end local function onOff(value) return value and "on" or "off" end task.spawn(function() while alive do local ok, reason = pcall(function() ui.status:Set(supported and ("ABA detected | " .. executor) or "Wrong game, features locked") ui.character:Set("Character: " .. tostring(Game.characterName(player)) .. (player.Team and (" | Team: " .. player.Team.Name) or "")) ui.performance:Set(string.format("FPS: %d | ping: %dms", math.floor(1 / math.max(timing.frame, 1e-3) + 0.5), math.floor(samplePing() * 1000 + 0.5))) local minutes = math.floor((os.clock() - session.started) / 60) ui.sessionTime:Set(string.format("time: %dh %dm", math.floor(minutes / 60), minutes % 60)) ui.sessionGold:Set("gold: +" .. math.floor(session.gold)) ui.sessionFights:Set(string.format("kills: %d | deaths: %d | damage: %d", session.kills, session.deaths, math.floor(session.damage))) local lines = ui.overview lines.farm:Set("Auto Farm: " .. onOff(farm.enabled) .. (farm.enabled and (" (" .. farm.target .. ")") or "")) lines.esp:Set("ESP: " .. onOff(esp.enabled) .. (esp.enabled and (" (" .. esp.shown .. " players)") or "")) lines.panel:Set("Target panel: " .. onOff(panel.enabled) .. (panel.subject and (" (" .. panel.subject .. ")") or "")) lines.anyBlackFlash:Set(string.format("Black Flash (any): %s (%d clicks)", onOff(anyBlackFlash.enabled), anyBlackFlash.clicks)) lines.yuji:Set(string.format("Yuji: black flash %s, divergent %s, skull smash %s", onOff(yuji.blackFlash), onOff(yuji.divergent), onOff(yuji.skull))) lines.nanami:Set(string.format("Nanami: auto hit %s (%d hits)", onOff(nanami.enabled), nanami.hits)) lines.yusuke:Set("Yusuke: gun sweep " .. onOff(yusuke.enabled)) lines.krillin:Set("Krillin: kiblast " .. onOff(krillin.enabled)) ui.farmStatus:Set(farm.enabled and farm.last or "off") ui.farmTarget:Set("target: " .. farm.target) ui.modeBar:Set(farm.ModeReady() and "mode bar: full" or "mode bar: charging") if tabOpen(farmTab) then ui.farmPreview:Set("would pick: " .. (farm.Preview() or "nobody")) end ui.espStatus:Set(esp.enabled and (esp.shown .. " players shown") or "off") ui.compStatus:Set(comp.enabled and ("focus: " .. (comp.focus or "none")) or "off") ui.anyBlackFlash:Set((anyBlackFlash.enabled and anyBlackFlash.last or "off") .. " | clicks: " .. anyBlackFlash.clicks) ui.yujiBlackFlash:Set((yuji.blackFlash and yuji.blackFlashLast or "off") .. " | clicks: " .. yuji.blackFlashClicks) ui.yujiDivergent:Set((yuji.divergent and yuji.divergentLast or "off") .. " | clicks: " .. yuji.divergentClicks) ui.yujiSkull:Set((yuji.skull and yuji.skullLast or "off") .. " | clicks: " .. yuji.skullClicks) ui.nanami:Set((nanami.enabled and nanami.last or "off") .. " | hits: " .. nanami.hits) ui.kokushibo:Set((kokushibo.enabled and kokushibo.last or "off") .. " | hits: " .. kokushibo.hits) ui.autoBlock:Set((autoBlock.enabled and autoBlock.last or "off") .. " | blocks: " .. autoBlock.blocks) ui.rejoin:Set(rejoin.last) ui.yusuke:Set((yusuke.enabled and yusuke.last or "off") .. " | shots: " .. yusuke.shots) ui.krillin:Set((krillin.enabled and krillin.last or "off") .. " | volleys: " .. krillin.volleys) if tabOpen(playerInfoTab) then refreshPlayerInfo() end end) if not ok then warn("[Catn Hub] status: " .. tostring(reason)) end task.wait(0.5) end end) return state ]=],mmm=[=[ if not game:IsLoaded() then game.Loaded:Wait() end local Players = game:GetService("Players") local RunService = game:GetService("RunService") local cas = game:GetService("ContextActionService") local uis = game:GetService("UserInputService") local GuiService = game:GetService("GuiService") local rs = game:GetService("ReplicatedStorage") local plr = Players.LocalPlayer while not plr do task.wait() plr = Players.LocalPlayer end plr:WaitForChild("PlayerGui") local genv = getgenv and getgenv() or _G if genv.__MMM_AUTOPLAY and genv.__MMM_AUTOPLAY.Destroy then pcall(genv.__MMM_AUTOPLAY.Destroy) end local BPUI = ... local function focused() if type(isrbxactive) ~= "function" then return true end local s, v = pcall(isrbxactive) return not s or v ~= false end local function strip(txt) return (tostring(txt or ""):gsub("<[^>]+>", ""):gsub("%s+", " ")) end local function actionName(lane) return lane .. "_FNF_Key" end local function laneBinds(lane) local info = cas:GetBoundActionInfo(actionName(lane)) local keys = {} if info and info.inputTypes then for _, k in ipairs(info.inputTypes) do if typeof(k) == "EnumItem" and k.EnumType == Enum.KeyCode and not k.Name:find("^Button") and not k.Name:find("^DPad") and not k.Name:find("^Thumbstick") then table.insert(keys, k.Name) end end end return keys, info ~= nil and info.inputTypes ~= nil end local inputObj local function grabInput(input) if input.KeyCode ~= Enum.KeyCode.Unknown then inputObj = input end end local VK = {Space = 0x20, Semicolon = 0xBA, Quote = 0xDE, Comma = 0xBC, Period = 0xBE, Slash = 0xBF, LeftBracket = 0xDB, RightBracket = 0xDD, BackSlash = 0xDC, Minus = 0xBD, Equals = 0xBB} for i = 0, 25 do VK[string.char(65 + i)] = 0x41 + i end for i, n in ipairs({"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"}) do VK[n] = 0x30 + i - 1 end local hasKeypress = type(keypress) == "function" and type(keyrelease) == "function" local lastPrime = -math.huge local function primeInput() if inputObj or not hasKeypress or os.clock() - lastPrime < 2 or not focused() then return end lastPrime = os.clock() pcall(function() keypress(0x7C) task.wait(0.03) keyrelease(0x7C) end) end local function backupKey(lane) if not hasKeypress then return end for _, k in ipairs((laneBinds(lane))) do if VK[k] then return VK[k] end end end local auto = { enabled = false, offsetMs = 0, presses = 0, status = "off", unbound = nil, method = "-", humanize = false, missChance = 2, goodChance = 10, jitter = 50, autoStart = false, aim = false, aimTarget = 96, } local live = {misses = nil, acc = nil, title = ""} local SICK, GOOD = 0.058, 0.1 local planVer = 0 local plans = setmetatable({}, {__mode = "k"}) local match = {speed = 1, extra = 0, last = -math.huge} local function updateMatchInfo() if os.clock() - match.last < 3 then return end match.last = os.clock() local matches = rs:FindFirstChild("Matches") if not matches then return end for _, m in ipairs(matches:GetChildren()) do for _, role in ipairs({"Owner", "Participant", "Opponent"}) do local r = m:FindFirstChild(role) if r and r:IsA("ObjectValue") and r.Value == plr and not m:GetAttribute("Finished") then local ns = r:FindFirstChild("NoteSpeed") local am = m:FindFirstChild("AccuracyMode") match.speed = (1 + (ns and tonumber(ns.Value) or 1)) * 0.5 match.extra = (am and am.Value == 1) and 0.029 or 0 return end end end end local function toPixels(laneFrame, units) return (units + match.extra) * match.speed * laneFrame.AbsoluteSize.Y end local function getPlan(note, laneFrame) local p = plans[note] if p and p.ver == planVer then return p end p = {ver = planVer, px = 0} if auto.aim then local acc = live.acc if acc and acc > auto.aimTarget + 1.5 and math.random() < 0.25 then p.skip, p.why = true, "skipped on purpose (accuracy target)" elseif acc and acc > auto.aimTarget then p.px = toPixels(laneFrame, (SICK + GOOD) / 2) end elseif auto.humanize then local roll = math.random() * 100 if roll < auto.missChance then p.skip, p.why = true, "skipped on purpose (humanize)" elseif roll < auto.missChance + auto.goodChance then p.px = toPixels(laneFrame, (SICK + GOOD) / 2) else p.px = (math.random() * 2 - 1) * auto.jitter / 100 * toPixels(laneFrame, SICK) end end plans[note] = p return p end local alive = true local conns = {} local lanes = {} local lastY = setmetatable({}, {__mode = "k"}) local hit = setmetatable({}, {__mode = "k"}) local retried = setmetatable({}, {__mode = "k"}) local arrowGui, side table.insert(conns, uis.InputBegan:Connect(grabInput)) table.insert(conns, uis.InputChanged:Connect(grabInput)) local function midY(g) return g.AbsolutePosition.Y + g.AbsoluteSize.Y / 2 end local MISS_FILE = "MMMAutoplay/misses.txt" local missLog = {entries = {}, events = {}, gui = nil, songStart = 0, lastMisses = 0, spikeAt = -math.huge, spikeMs = 0} local flagged = setmetatable({}, {__mode = "k"}) local function noteEvent(lane, why) table.insert(missLog.events, {at = os.clock(), lane = lane, why = why}) if #missLog.events > 40 then table.remove(missLog.events, 1) end end local function addMiss(text) table.insert(missLog.entries, text) if #missLog.entries > 200 then table.remove(missLog.entries, 1) end if type(appendfile) == "function" then pcall(function() if type(isfolder) == "function" and type(makefolder) == "function" and not isfolder("MMMAutoplay") then makefolder("MMMAutoplay") end appendfile(MISS_FILE, text .. "\n") end) end end local function readStats() local s = arrowGui and arrowGui:FindFirstChild("Stats") local t = s and strip(s.Text) or "" live.misses = tonumber(t:match("Misses:%s*(%d+)")) live.acc = tonumber(t:match("Accuracy:%s*([%d%.]+)")) end local function trackMisses(now) if missLog.gui ~= arrowGui then missLog.gui, missLog.songStart, missLog.lastMisses, missLog.events = arrowGui, now, live.misses or 0, {} end local t = arrowGui and arrowGui:FindFirstChild("Title") local title = t and (strip(t.Text):gsub("%s*%[[%d:]+%]%s*$", "")) or "" if title == "" then title = "?" end local m = live.misses if not m then return end if m < missLog.lastMisses then missLog.lastMisses = m end while missLog.lastMisses < m do missLog.lastMisses = missLog.lastMisses + 1 local ev for i = #missLog.events, 1, -1 do local e = missLog.events[i] if not e.used and now - e.at < 0.6 then ev = e break end end if ev then ev.used = true end local why = ev and ev.why if not why and now - (missLog.blockedAt or -math.huge) < 1.5 then why = "roblox wasn't focused and the script had no input object yet, so it couldn't press" elseif not why and now - missLog.spikeAt < 1.5 then why = string.format("game froze for %d ms, notes went past before anything could press", missLog.spikeMs) end if why and now - (missLog.unfocusedAt or -math.huge) < 1.5 then why = why .. " (roblox was unfocused)" end local secs = now - missLog.songStart addMiss(string.format("%s %d:%02d miss %d %s %s", title, math.floor(secs / 60), math.floor(secs % 60), missLog.lastMisses, ev and ev.lane or "?", why or "no cause seen (the game called it a miss)")) end end local function send(lane, down) if inputObj then local s = pcall(function() cas:CallFunction(lane.action, down and Enum.UserInputState.Begin or Enum.UserInputState.End, inputObj) end) if s then auto.method = "direct (any bind)" return true end end if lane.vk then if down then keypress(lane.vk) else keyrelease(lane.vk) end auto.method = "key presses" return true end return false end local function release(lane) if lane.down then pcall(send, lane, false) end lane.down = false end local function releaseAll() for _, l in pairs(lanes) do release(l) end end local function press(lane) release(lane) lane.down = send(lane, true) lane.pressedAt = os.clock() return lane.down end local arrowCache, arrowCheck = nil, 0 local function findArrowGui() if arrowCache and arrowCache.Parent then return arrowCache end if os.clock() - arrowCheck < 0.5 then return nil end arrowCheck = os.clock() arrowCache = plr.PlayerGui:FindFirstChild("ArrowGui", true) return arrowCache end local function getSide(gui) local opp = gui:FindFirstChild("OpponentStats") local best, gap for _, n in ipairs({"Left", "Right"}) do local s = gui:FindFirstChild(n) if s and s:FindFirstChild("Notes") then local g = opp and math.abs(s.AbsolutePosition.X - opp.AbsolutePosition.X) or 0 if not gap or g > gap then best, gap = s, g end end end return best end local function step(dt) if dt > 0.1 then missLog.spikeAt, missLog.spikeMs = os.clock(), math.floor(dt * 1000 + 0.5) end if not auto.enabled then return end if not arrowGui or not arrowGui.Parent then releaseAll() table.clear(lanes) auto.unbound = nil arrowGui, side = findArrowGui(), nil if not arrowGui then auto.status = "waiting for a song" return end end side = side or getSide(arrowGui) local receptors = side and side:FindFirstChild("MainArrowContainer") local notes = side and side:FindFirstChild("Notes") local holds = side and side:FindFirstChild("LongNotes") if not receptors or not notes then auto.status = "waiting for a song" return end if not focused() then missLog.unfocusedAt = os.clock() end if uis:GetFocusedTextBox() or (not inputObj and not focused()) then if not inputObj and not focused() then missLog.blockedAt = os.clock() end releaseAll() auto.status = uis:GetFocusedTextBox() and "paused (typing)" or "paused (click into roblox once, after that it works in the background)" return end auto.status = "playing" updateMatchInfo() local now = os.clock() readStats() trackMisses(now) local offset = auto.offsetMs / 1000 for _, laneFrame in ipairs(notes:GetChildren()) do local name = laneFrame.Name local rec = receptors:FindFirstChild(name) local lane = lanes[name] if not lane then local _, bound = laneBinds(name) if bound then lane = {action = actionName(name), vk = backupKey(name), down = false, pressedAt = 0, holdUntil = 0} lanes[name] = lane if auto.unbound == name then auto.unbound = nil end else auto.unbound = name end end if rec and lane then local line = midY(rec) local window = math.max(rec.AbsoluteSize.Y * 0.35, toPixels(laneFrame, GOOD)) local pressCount = 0 for _, note in ipairs(laneFrame:GetChildren()) do if note:IsA("GuiObject") and note.Visible then local y = midY(note) local prev = lastY[note] lastY[note] = y if prev and math.abs(y - prev) > rec.AbsoluteSize.Y * 2 then prev, hit[note], plans[note], retried[note], flagged[note] = nil, nil, nil, nil, nil end local p = getPlan(note, laneFrame) local again = hit[note] and not retried[note] and now - hit[note] > 0.025 if prev and dt > 0 and (not hit[note] or again) and not p.skip then local vel = (y - prev) / dt local speed = math.abs(vel) if speed > 5 then local left = (line - y) * (vel > 0 and 1 or -1) if left <= speed * dt * 0.5 + speed * offset + p.px and left > -window then if again then retried[note] = true end hit[note] = now pressCount = pressCount + 1 end end end if prev and dt > 0 and not flagged[note] then local vel = (y - prev) / dt if math.abs(vel) > 5 and (line - y) * (vel > 0 and 1 or -1) <= -window then flagged[note] = true local why if p.skip then why = p.why or "skipped on purpose" elseif hit[note] then why = "pressed, but the game didn't take it" elseif dt > 0.05 then why = string.format("went past during a lag spike (%d ms frame)", math.floor(dt * 1000 + 0.5)) else why = "never pressed" end noteEvent(name, why) end end end end local holdLane = holds and holds:FindFirstChild(name) if holdLane then for _, piece in ipairs(holdLane:GetChildren()) do if piece:IsA("GuiObject") and piece.Visible then local top = piece.AbsolutePosition.Y if top <= line + 4 and top + piece.AbsoluteSize.Y >= line - 4 then lane.holdUntil = now + 0.06 break end end end end if pressCount > 0 then for _ = 1, pressCount do if press(lane) then auto.presses = auto.presses + 1 end end elseif lane.down and now - lane.pressedAt > 0.04 and now > lane.holdUntil then release(lane) end end end end table.insert(conns, RunService.RenderStepped:Connect(function(dt) local s, err = pcall(step, dt) if not s then auto.status = "error: " .. tostring(err) releaseAll() end end)) local lastStart = 0 local function autoStart() if not auto.autoStart or os.clock() - lastStart < 2 then return end if type(mousemoveabs) ~= "function" or type(mouse1click) ~= "function" or not focused() then return end local gui = arrowGui and arrowGui.Parent and arrowGui or findArrowGui() local btn = gui and gui:FindFirstChild("Start") if not btn or not btn:IsA("GuiButton") or not btn.Visible then return end local sg = btn:FindFirstAncestorOfClass("ScreenGui") local inset = (sg and sg.IgnoreGuiInset) and Vector2.zero or GuiService:GetGuiInset() local pos = btn.AbsolutePosition + btn.AbsoluteSize / 2 + inset lastStart = os.clock() mousemoveabs(math.floor(pos.X), math.floor(pos.Y)) task.wait(0.05) mouse1click() end local LOBBY = {PlayerType = 2, AccessType = 1, MatchType = 3, AccuracyMode = 2, ModChartsEnabled = false} local lobby = { auto = false, pick = false, category = nil, song = nil, difficulty = nil, status = "off", lastCreate = -math.huge, idleSince = nil, picked = 0, closeResults = false, resultsDelay = 3, } local mods = {} local function loadMods() if mods.noteGame and mods.class then return true end pcall(function() mods.noteGame = require(plr.PlayerScripts.Start.Menu.Freeplay.NoteGame) mods.effects = require(rs.Modules.CommonEffects) mods.songs = require(rs.Modules.Songs) if type(filtergc) == "function" then mods.class = filtergc("table", {Keys = {"_StartSongSelect", "_LoadSong"}}, true) end end) return mods.noteGame ~= nil and mods.class ~= nil end local function hiddenGuis() return rs.Assets:FindFirstChild("GUIs") end local function songSelect() if not loadMods() then return end local fn = rawget(mods.class, "_StartSongSelect") local s, sel, frame, timer = pcall(function() return debug.getupvalue(fn, 3), debug.getupvalue(fn, 6), debug.getupvalue(fn, 23) end) if not s or type(sel) ~= "table" or typeof(frame) ~= "Instance" or type(timer) ~= "table" then return end return sel, frame, timer end local function myMatch() local matches = rs:FindFirstChild("Matches") local mine = matches and matches:FindFirstChild(tostring(plr.UserId)) if mine and not mine:GetAttribute("Finished") then return mine, true end if matches then for _, m in ipairs(matches:GetChildren()) do if not m:GetAttribute("Finished") then for _, role in ipairs({"Owner", "Participant", "Opponent"}) do local r = m:FindFirstChild(role) if r and r:IsA("ObjectValue") and r.Value == plr then return m, false end end end end end end local function hasOpponent(m) local o = m and m:FindFirstChild("Opponent") return o ~= nil and o:IsA("ObjectValue") and o.Value ~= nil end local function makeLobby() if not loadMods() then lobby.status = "couldn't load the game's match code" return end lobby.lastCreate = os.clock() local canCreate = rs:FindFirstChild("Events") and rs.Events:FindFirstChild("CanCreateMatch") if canCreate then local s, allowed, wait = pcall(canCreate.InvokeServer, canCreate) if s and allowed == false then lobby.status = "game won't let you host yet (" .. tostring(wait) .. ")" return end end local s, ev = pcall(function() return mods.noteGame:CreateMatch(table.clone(LOBBY)) end) if not s then lobby.status = "create failed: " .. tostring(ev) return end pcall(function() ev:Connect(function(stage) if mods.effects and stage == mods.effects.BlackTransitionEvent.Halfway then local menu = plr.PlayerGui:FindFirstChild("FreeplayMenu", true) if menu then menu.Parent = hiddenGuis() end end end) end) lobby.status = "lobby created, waiting for a player" end local function pickedSong() local cat = mods.songs and lobby.category and mods.songs[lobby.category] local song = cat and cat.Songs and cat.Songs[lobby.song] if song and type(song.DifficultyInfo) == "table" and song.DifficultyInfo[lobby.difficulty] then return lobby.category, lobby.song, lobby.difficulty end end local answered = false local function pickSong() if not lobby.pick then return end local sel, frame, timer = songSelect() if not sel then return end local open = frame.Parent ~= nil and frame.Parent ~= hiddenGuis() if not open then answered = false return end if answered then return end local m, owner = myMatch() if not m or not hasOpponent(m) then return end local cat, song, diff = pickedSong() if not cat then lobby.status = "pick a valid song first" return end answered = true task.wait(0.5) sel.Category, sel.Song, sel.Difficulty = cat, song, diff pcall(function() timer:Stop() end) lobby.picked = lobby.picked + 1 lobby.status = "picked " .. song .. " (" .. diff .. ")" .. (owner and "" or " as a vote") end local resultsAt, lastClose = nil, -math.huge local function closeResults() if not lobby.closeResults or type(getconnections) ~= "function" or not loadMods() then return end local s, gui = pcall(debug.getupvalue, rawget(mods.class, "_ToResults"), 3) if not s or typeof(gui) ~= "Instance" then return end if gui.Parent == nil or gui.Parent == hiddenGuis() then resultsAt = nil return end resultsAt = resultsAt or os.clock() if os.clock() - resultsAt < lobby.resultsDelay or os.clock() - lastClose < 5 then return end local btn = gui:FindFirstChild("Background") and gui.Background:FindFirstChild("Return") if not btn then return end lastClose, resultsAt = os.clock(), nil for _, c in ipairs(getconnections(btn.MouseButton1Click)) do if c.Function then task.spawn(c.Function) end end lobby.status = "closed results" end local function lobbyTick() local m = myMatch() if m or findArrowGui() then lobby.idleSince = nil if lobby.auto and m and not hasOpponent(m) then lobby.status = "waiting for a player to join" end return end if not lobby.auto then lobby.status = "off" return end lobby.idleSince = lobby.idleSince or os.clock() if os.clock() - lobby.idleSince >= 4 and os.clock() - lobby.lastCreate >= 15 then lobby.status = "creating lobby..." makeLobby() else lobby.status = "creating a lobby shortly" end end local LOG_FILE = "MMMAutoplay/songs.txt" local songLog = {} local cur local HttpService = game:GetService("HttpService") local hook = {url = "", on = false, status = "off"} local function validHook(url) return url:match("^https://[%w%.]*discord%.com/api/webhooks/%d+/[%w_%-]+$") ~= nil or url:match("^https://[%w%.]*discordapp%.com/api/webhooks/%d+/[%w_%-]+$") ~= nil end local function postResult(title, stats, judgements, why) local send = request or http_request or (syn and syn.request) or (http and http.request) if not send then hook.status = "this executor can't send web requests" return false end if not validHook(hook.url) then hook.status = "that isn't a discord webhook link" return false end local fields = {{name = "Judgements", value = judgements ~= "" and judgements or "-", inline = false}} if why and why ~= "" then table.insert(fields, {name = "Misses", value = why, inline = false}) end local body = HttpService:JSONEncode({ username = "Catn Hub", embeds = {{ title = title ~= "" and title or "Song finished", description = stats, color = 16747032, fields = fields, footer = {text = "MMM Autoplay"}, timestamp = DateTime.now():ToIsoDate(), }}, }) local ok, res = pcall(send, {Url = hook.url, Method = "POST", Headers = {["Content-Type"] = "application/json"}, Body = body}) local code = ok and type(res) == "table" and res.StatusCode or nil if code and code >= 200 and code < 300 then hook.status = "sent " .. os.date("%H:%M") return true end hook.status = "discord refused it (" .. tostring(code or res) .. ")" return false end local function missSummary(title) local counts, order = {}, {} for _, line in ipairs(missLog.entries) do if line:sub(1, #title) == title then local why = line:match("miss %d+ %S+ (.+)$") or "?" if not counts[why] then counts[why] = 0 table.insert(order, why) end counts[why] = counts[why] + 1 end end local out = {} for _, why in ipairs(order) do table.insert(out, counts[why] .. "x " .. why) end return table.concat(out, "\n") end local function saveSong() if not cur then return end if hook.on then local c = cur task.spawn(postResult, c.title, c.stats, c.judgements, missSummary(c.title)) end local line = os.date("%m/%d %H:%M") .. " " .. cur.title .. " | " .. cur.stats .. (cur.judgements ~= "" and (" | " .. cur.judgements) or "") table.insert(songLog, 1, line) if #songLog > 10 then table.remove(songLog) end if type(appendfile) == "function" and type(makefolder) == "function" then pcall(function() if type(isfolder) == "function" and not isfolder("MMMAutoplay") then makefolder("MMMAutoplay") end appendfile(LOG_FILE, line .. "\n") end) end cur = nil end local function watchSong() local gui = arrowGui and arrowGui.Parent and arrowGui or findArrowGui() local stats = gui and gui:FindFirstChild("Stats") and strip(gui.Stats.Text) or "" if stats:find("Score: %d") then cur = { title = strip(gui:FindFirstChild("Title") and gui.Title.Text):gsub("%s*%[[%d:]+%]%s*$", ""), stats = stats, judgements = strip(gui:FindFirstChild("Judgements") and gui.Judgements.Text):gsub("^Judgements: %-+ ", ""), } elseif cur then saveSong() end end local window = BPUI:CreateWindow({Version = "1.1.1", Title = "MMM Autoplay", Subtitle = "Monday Morning Misery", Icon = "zap", Theme = "Void", Accent = Color3.fromRGB(143, 112, 236), ToggleKey = Enum.KeyCode.RightShift, ShowSettings = true, ConfigFolder = "MMMAutoplay", Watermark = false, CloseBehavior = "Hide", OnDestroy = function() alive = false auto.enabled = false releaseAll() for _, c in ipairs(conns) do c:Disconnect() end end, }) local state = {Auto = auto, MatchInfo = match, Lobby = lobby} state.ResetPlans = function() planVer = planVer + 1 end state.Destroy = function() pcall(function() window:Destroy() end) end genv.__MMM_AUTOPLAY = state local tab = window:CreateTab({Name = "Autoplay", Icon = "zap"}) local main = tab:CreateSection("Autoplay") local toggle = main:AddToggle({Name = "Auto play", Default = false, Flag = "autoplay_enabled", Description = "Hits every note on your side, holds included.", Callback = function(v) auto.enabled = v == true and alive if not auto.enabled then releaseAll() auto.status = "off" end end}) main:AddKeybind({Name = "Keybind", Default = Enum.KeyCode.F1, Mode = "Press", Flag = "autoplay_key", Callback = function() toggle:Set(not auto.enabled) end}) local statusLbl = main:AddLabel({Text = "off", Style = "Sub"}) local songLbl = main:AddLabel({Text = "song: -", Style = "Sub"}) local statsLbl = main:AddLabel({Text = "-", Style = "Sub"}) local ctl = {} local timing = tab:CreateSection("Timing") ctl.offset = timing:AddSlider({Name = "Offset", Min = -50, Max = 50, Default = 0, Increment = 1, Suffix = " ms", Flag = "autoplay_offset", Description = "Positive presses earlier. Leave at 0 unless hits come out as Good.", Callback = function(v) auto.offsetMs = tonumber(v) or 0 end}) local aimSec = tab:CreateSection("Accuracy target") local function changed() planVer = planVer + 1 end ctl.aim = aimSec:AddToggle({Name = "Aim for an accuracy", Default = false, Flag = "autoplay_aim", Description = "Plays perfect while under the target and lets some notes slip while over it. Replaces Humanize while on.", Callback = function(v) auto.aim = v == true changed() end}) ctl.aimTarget = aimSec:AddSlider({Name = "Target", DependsOn = ctl.aim, Min = 80, Max = 100, Default = 96, Increment = 0.5, Suffix = " %", Flag = "autoplay_aim_target", Callback = function(v) auto.aimTarget = tonumber(v) or 96 changed() end}) local human = tab:CreateSection("Humanize") ctl.humanize = human:AddToggle({Name = "Humanize", Default = false, Flag = "autoplay_humanize", Description = "Mixes in misses, Goods and small timing errors so it doesn't play perfectly.", Callback = function(v) auto.humanize = v == true changed() end}) ctl.miss = human:AddSlider({Name = "Miss chance", DependsOn = ctl.humanize, Min = 0, Max = 15, Default = 2, Increment = 1, Suffix = " %", Flag = "autoplay_miss", Callback = function(v) auto.missChance = tonumber(v) or 0 changed() end}) ctl.good = human:AddSlider({Name = "Good chance", DependsOn = ctl.humanize, Min = 0, Max = 40, Default = 10, Increment = 1, Suffix = " %", Flag = "autoplay_good", Callback = function(v) auto.goodChance = tonumber(v) or 0 changed() end}) ctl.jitter = human:AddSlider({Name = "Timing jitter", DependsOn = ctl.humanize, Min = 0, Max = 80, Default = 50, Increment = 5, Suffix = " %", Flag = "autoplay_jitter", Description = "Random error on normal hits, as a share of the Sick window, so they stay Sick.", Callback = function(v) auto.jitter = tonumber(v) or 0 changed() end}) local PRESET_FILE = "MMMAutoplay/presets.json" local BUILT_IN = { {name = "Perfect", s = {offset = 0, humanize = false, aim = false}}, {name = "Looks human", s = {offset = 0, humanize = true, miss = 2, good = 10, jitter = 50, aim = false}}, {name = "Sloppy", s = {offset = 0, humanize = true, miss = 6, good = 25, jitter = 70, aim = false}}, {name = "Aim for 95%", s = {offset = 0, aim = true, aimTarget = 95}}, } local userPresets = {} pcall(function() if type(isfile) == "function" and isfile(PRESET_FILE) then local data = HttpService:JSONDecode(readfile(PRESET_FILE)) if type(data) == "table" then userPresets = data end end end) local function savePresets() pcall(function() if type(isfolder) == "function" and type(makefolder) == "function" and not isfolder("MMMAutoplay") then makefolder("MMMAutoplay") end writefile(PRESET_FILE, HttpService:JSONEncode(userPresets)) end) end local function presetNames() local names = {} for _, p in ipairs(BUILT_IN) do table.insert(names, p.name) end local mine = {} for name in pairs(userPresets) do table.insert(mine, name) end table.sort(mine, function(a, b) return a:lower() < b:lower() end) for _, n in ipairs(mine) do table.insert(names, n) end return names end local function findPreset(name) for _, p in ipairs(BUILT_IN) do if p.name == name then return p.s, true end end return userPresets[name], false end local function currentSettings() return {offset = auto.offsetMs, humanize = auto.humanize, miss = auto.missChance, good = auto.goodChance, jitter = auto.jitter, aim = auto.aim, aimTarget = auto.aimTarget} end local function applySettings(s) if type(s) ~= "table" then return false end local function num(v, lo, hi) v = tonumber(v) return v and math.clamp(v, lo, hi) or nil end if num(s.offset, -50, 50) then ctl.offset:Set(num(s.offset, -50, 50)) end if num(s.miss, 0, 15) then ctl.miss:Set(num(s.miss, 0, 15)) end if num(s.good, 0, 40) then ctl.good:Set(num(s.good, 0, 40)) end if num(s.jitter, 0, 80) then ctl.jitter:Set(num(s.jitter, 0, 80)) end if num(s.aimTarget, 80, 100) then ctl.aimTarget:Set(num(s.aimTarget, 80, 100)) end if type(s.humanize) == "boolean" then ctl.humanize:Set(s.humanize) end if type(s.aim) == "boolean" then ctl.aim:Set(s.aim) end return true end local presetSec = tab:CreateSection("Presets") local chosenPreset = "Perfect" local presetDrop = presetSec:AddDropdown({Name = "Preset", Options = presetNames(), Default = "Perfect", Callback = function(v) chosenPreset = v end}) presetSec:AddButton({Name = "Use this preset", ButtonText = "Apply", Callback = function() local s = findPreset(chosenPreset) if applySettings(s) then window:Notify({Title = "Preset", Content = chosenPreset .. " applied.", Type = "Success", Duration = 3}) end end}) local newName = "" presetSec:AddInput({Name = "Name", Placeholder = "My preset", Callback = function(t) newName = tostring(t or "") end}) presetSec:AddButton({Name = "Save current settings", ButtonText = "Save", Callback = function() local name = newName:gsub("^%s+", ""):gsub("%s+$", "") if name == "" then window:Notify({Title = "Preset", Content = "Type a name first.", Type = "Warning", Duration = 3}) return end local _, builtIn = findPreset(name) if builtIn then window:Notify({Title = "Preset", Content = "That name is taken by a built-in preset.", Type = "Warning", Duration = 3}) return end userPresets[name] = currentSettings() savePresets() presetDrop:Refresh(presetNames()) window:Notify({Title = "Preset", Content = "Saved " .. name .. ".", Type = "Success", Duration = 3}) end}) presetSec:AddButton({Name = "Delete selected preset", ButtonText = "Delete", Style = "Danger", Callback = function() local _, builtIn = findPreset(chosenPreset) if builtIn or not userPresets[chosenPreset] then window:Notify({Title = "Preset", Content = "Built-in presets can't be deleted.", Type = "Warning", Duration = 3}) return end userPresets[chosenPreset] = nil savePresets() presetDrop:Refresh(presetNames()) window:Notify({Title = "Preset", Content = "Deleted " .. chosenPreset .. ".", Type = "Info", Duration = 3}) end}) presetSec:AddButton({Name = "Copy current settings as a code", ButtonText = "Copy", Callback = function() local code = "MMM:" .. HttpService:JSONEncode(currentSettings()) if type(setclipboard) == "function" and pcall(setclipboard, code) then window:Notify({Title = "Preset", Content = "Code copied. Anyone can paste it below to get these settings.", Type = "Success", Duration = 4}) else window:Notify({Title = "Preset", Content = code, Type = "Info", Duration = 12}) end end}) presetSec:AddInput({Name = "Paste a code", Placeholder = "MMM:{...}", Callback = function(t, enter) t = tostring(t or "") if not enter or t == "" then return end local ok, s = pcall(HttpService.JSONDecode, HttpService, (t:gsub("^%s*MMM:", ""))) if ok and applySettings(s) then window:Notify({Title = "Preset", Content = "Settings from the code applied. Save them to keep them as a preset.", Type = "Success", Duration = 4}) else window:Notify({Title = "Preset", Content = "That code doesn't look right.", Type = "Error", Duration = 3}) end end}) local extras = tab:CreateSection("Extras") extras:AddToggle({Name = "Auto start", Default = false, Flag = "autoplay_autostart", Description = "Clicks Start when it shows up. Needs Roblox focused.", Callback = function(v) auto.autoStart = v == true end}) local lobbyTab = window:CreateTab({Name = "Lobby", Icon = "users"}) local lob = lobbyTab:CreateSection("Auto lobby") lob:AddToggle({Name = "Auto create lobby", Default = false, Flag = "lobby_auto", Description = "Hosts a match whenever you're not in one: Right side, everyone can join, least misses.", Callback = function(v) lobby.auto = v == true lobby.idleSince = nil end}) lob:AddToggle({Name = "Auto pick song", Default = false, Flag = "lobby_pick", Description = "Picks the song below once another player joins and song select opens.", Callback = function(v) lobby.pick = v == true end}) local closeToggle = lob:AddToggle({Name = "Auto close results", Default = false, Flag = "lobby_close_results", Description = "Leaves the results screen after a match so a new lobby can be made.", Callback = function(v) lobby.closeResults = v == true end}) lob:AddSlider({Name = "Results delay", DependsOn = closeToggle, Min = 0, Max = 15, Default = 3, Increment = 1, Suffix = " s", Flag = "lobby_results_delay", Description = "How long to show the results before closing them.", Callback = function(v) lobby.resultsDelay = tonumber(v) or 3 end}) local lobbyLbl = lob:AddLabel({Text = "off", Style = "Sub"}) lob:AddLabel({Text = "auto start is ignored while auto lobby is on", Style = "Sub"}) local songSec = lobbyTab:CreateSection("Song") loadMods() local songs = mods.songs or {} local function sortedKeys(t) local out = {} if type(t) == "table" then for k in pairs(t) do table.insert(out, tostring(k)) end end table.sort(out, function(a, b) return a:lower() < b:lower() end) return out end local cats = {} for name, c in pairs(songs) do if type(c) == "table" and type(c.Songs) == "table" then table.insert(cats, name) end end table.sort(cats, function(a, b) return a:lower() < b:lower() end) local songDrop, diffDrop songSec:AddDropdown({Name = "Category", Options = cats, Flag = "lobby_category", Searchable = true, Callback = function(v) lobby.category = v if songDrop then songDrop:Refresh(sortedKeys(songs[v] and songs[v].Songs)) end lobby.song, lobby.difficulty = nil, nil if diffDrop then diffDrop:Refresh({}) end end}) songDrop = songSec:AddDropdown({Name = "Song", Options = {}, Flag = "lobby_song", Searchable = true, Callback = function(v) lobby.song = v local c = songs[lobby.category] local data = c and c.Songs and c.Songs[v] local diffs = sortedKeys(data and data.DifficultyInfo) if diffDrop then diffDrop:Refresh(diffs) if #diffs == 1 then diffDrop:Set(diffs[1]) end end end}) diffDrop = songSec:AddDropdown({Name = "Difficulty", Options = {}, Flag = "lobby_difficulty", Callback = function(v) lobby.difficulty = v end}) local songCheck = songSec:AddLabel({Text = "no song chosen", Style = "Sub"}) local logSec = tab:CreateSection("Song log") local logText = logSec:AddParagraph({Title = "Last songs", Content = "none yet"}) logSec:AddLabel({Text = "also saved to workspace/" .. LOG_FILE, Style = "Sub"}) local bindSec = tab:CreateSection("Your binds") local bindsLbl = bindSec:AddLabel({Text = "start a song to read them", Style = "Sub"}) local inputLbl = bindSec:AddLabel({Text = "input: -", Style = "Sub"}) local missTab = window:CreateTab({Name = "Miss log", Icon = "list"}) local missSec = missTab:CreateSection("Misses") local missText = missSec:AddParagraph({Title = "Latest misses", Content = "none yet"}) missSec:AddButton({Name = "Copy miss log", Desc = "Paste it to whoever is fixing the script", ButtonText = "Copy", Callback = function() local text = #missLog.entries > 0 and table.concat(missLog.entries, "\n") or "no misses logged" if type(setclipboard) == "function" and pcall(setclipboard, text) then window:Notify({Title = "Miss log", Content = #missLog.entries .. " lines copied.", Type = "Success", Duration = 3}) else window:Notify({Title = "Miss log", Content = "This executor can't copy. It's also saved to workspace/" .. MISS_FILE, Type = "Info", Duration = 6}) end end}) missSec:AddButton({Name = "Clear", ButtonText = "Clear", Callback = function() table.clear(missLog.entries) window:Notify({Title = "Miss log", Content = "Cleared.", Type = "Info", Duration = 2}) end}) missSec:AddLabel({Text = "each line: song, time into the song, miss number, lane, why. also saved to workspace/" .. MISS_FILE, Style = "Sub"}) local discordTab = window:CreateTab({Name = "Discord", Icon = "message-circle"}) local hookSec = discordTab:CreateSection("Post results") hookSec:AddToggle({Name = "Post after each song", Default = false, Flag = "hook_on", Description = "Sends the song, score, accuracy, judgements and why any misses happened.", Callback = function(v) hook.on = v == true end}) hookSec:AddInput({Name = "Webhook link", Placeholder = "https://discord.com/api/webhooks/...", Flag = "hook_url", Callback = function(t) hook.url = (tostring(t or ""):gsub("%s", "")) hook.status = hook.url == "" and "no link yet" or (validHook(hook.url) and "ready" or "that isn't a discord webhook link") end}) hookSec:AddButton({Name = "Send a test", ButtonText = "Send", Callback = function() task.spawn(function() local ok = postResult("Test from MMM Autoplay", "If you can read this, results will show up here.", "", "") window:Notify({Title = "Discord", Content = ok and "Test sent." or hook.status, Type = ok and "Success" or "Error", Duration = 4}) end) end}) local hookLbl = hookSec:AddLabel({Text = "no link yet", Style = "Sub"}) hookSec:AddLabel({Text = "Server Settings > Integrations > Webhooks > New Webhook > Copy Webhook URL", Style = "Sub"}) local function laneOrder() local rec = side and side:FindFirstChild("MainArrowContainer") local list = {} if rec then for _, r in ipairs(rec:GetChildren()) do if r:IsA("GuiObject") then table.insert(list, r) end end table.sort(list, function(a, b) return a.Position.X.Scale < b.Position.X.Scale end) end local names = {} for _, r in ipairs(list) do table.insert(names, r.Name) end if #names == 0 then names = {"Left", "Down", "Up", "Right"} end return names end local function bindsText() local parts = {} for _, n in ipairs(laneOrder()) do local keys = laneBinds(n) if #keys > 0 then table.insert(parts, n .. ": " .. table.concat(keys, " / ")) end end return #parts > 0 and table.concat(parts, " ") or "start a song to read them" end task.spawn(function() while alive do task.spawn(pcall, primeInput) pcall(watchSong) pcall(closeResults) pcall(lobbyTick) task.spawn(pcall, pickSong) if not lobby.auto then pcall(autoStart) end pcall(function() logText:SetContent(#songLog > 0 and table.concat(songLog, "\n") or "none yet") local last = {} for i = math.max(1, #missLog.entries - 7), #missLog.entries do table.insert(last, missLog.entries[i]) end missText:SetContent(#last > 0 and table.concat(last, "\n") or "none yet") hookLbl:Set(hook.status) lobbyLbl:Set(lobby.status .. (lobby.picked > 0 and (" | songs picked: " .. lobby.picked) or "")) local c, s, d = pickedSong() songCheck:Set(c and ("ready: " .. s .. " (" .. d .. ")") or "no song chosen") end) pcall(function() local txt = auto.enabled and auto.status or "off" if auto.unbound then txt = txt .. " | no usable key for lane " .. auto.unbound end statusLbl:Set(txt .. " | presses: " .. auto.presses) bindsLbl:Set(bindsText()) inputLbl:Set("input: " .. (inputObj and "direct (works with any bind)" or "waiting for mouse movement") .. (auto.method ~= "-" and (" | last used: " .. auto.method) or "")) if arrowGui and arrowGui.Parent then songLbl:Set("song: " .. strip(arrowGui:FindFirstChild("Title") and arrowGui.Title.Text)) local j = strip(arrowGui:FindFirstChild("Judgements") and arrowGui.Judgements.Text):gsub("^Judgements: %-+ ", "") statsLbl:Set(strip(arrowGui:FindFirstChild("Stats") and arrowGui.Stats.Text) .. " | " .. j) else songLbl:Set("song: -") statsLbl:Set("-") end end) task.wait(0.5) end end) window:SelectTab("Autoplay") pcall(function() window:Notify({Title = "MMM Autoplay", Content = "loaded, F1 to toggle", Type = "Success", Duration = 4}) end) return state ]=],cfae=[=[ if not game:IsLoaded() then game.Loaded:Wait() end local Players = game:GetService("Players") local RunService = game:GetService("RunService") local VirtualUser = game:GetService("VirtualUser") local StarterPlayer = game:GetService("StarterPlayer") local rs = game:GetService("ReplicatedStorage") local plr = Players.LocalPlayer while not plr do task.wait() plr = Players.LocalPlayer end local genv = getgenv and getgenv() or _G if genv.__CFAE_FARM and genv.__CFAE_FARM.Destroy then pcall(genv.__CFAE_FARM.Destroy) end local BPUI = ... local src = rs:WaitForChild("src") local knit = require(src:WaitForChild("Packages"):WaitForChild("knit")) pcall(function() knit.OnStart():await() end) local function elevate() if setthreadidentity then pcall(setthreadidentity, 8) end end local function getController(name) local okc, c = pcall(knit.GetController, name) if okc then return c end end local function getService(name) local oks, s = pcall(knit.GetService, name) if oks then return s end end local config = src:WaitForChild("GameConfiguration") local zoneConfig = require(config.Gameplay.zoneConfig) local eggConfig = require(config.Gameplay.eggConfig) local animalConfig = require(config.Gameplay.animalConfig) local staminaUpgradeConfig = require(config.Economy.staminaUpgradeConfig) local treadmillConfig = require(config.Economy.treadmillConfig) local baseUpgradeConfig = require(config.Economy.baseUpgradeConfig) local rebirthConfig = require(config.Economy.rebirthConfig) local guardConfig = require(config.Gameplay.guardConfig) local guardGeometry = require(src.utility.guardGeometry) local dayCycle = require(src.utility.dayCycle) local backpackLimits = require(src.utility.backpackLimits) local speedCurve = require(src.utility.speedCurve) local Data = getController("DataController") local Bases = getController("BaseController") local Hatcher = getController("EggHatchController") local Loadout = getController("AnimalLoadoutController") local Treadmill = getController("TreadmillController") local Gifts = getController("GiftPlayTimeController") local Jetpack = getController("JetpackController") local SpeedState = getController("SpeedStateController") local GuardAi = getController("GuardController") local svc = {} for _, name in ipairs({"EggPlacementService", "AnimalSellService", "StaminaUpgradeService", "TreadmillService", "BaseUpgradeService", "RebirthService", "DailyRewardsService", "GiftPlayTimeService", "IndexService", "CashFlowService", "DayCycleService", "HalloweenShopService"}) do svc[name] = getService(name) end local charContext = StarterPlayer:WaitForChild("PlayerModule"):WaitForChild("InputContexts"):WaitForChild("CharacterContext") local MoveAction = charContext:WaitForChild("MoveAction") local JumpAction = charContext:WaitForChild("JumpAction") local alive = true local conns = {} local function connect(signal, fn) local c = signal:Connect(fn) table.insert(conns, c) return c end local settings = { pick = "Most valuable", waitForGuard = true, escape = "Best", halloween = true, guardWait = 45, guardMargin = 2, maxEscape = 70, betterOnly = false, nights = true, idle = "Train on the treadmill", trainOnly = false, place = true, hatch = true, equip = true, sell = false, keepSpare = 5, buyStamina = true, buyTreadmill = true, buyBase = true, reserve = 0, rebirth = true, multipliers = true, rewards = true, candyEggs = true, antiAfk = true, } local farm = {enabled = false, run = 0, status = "off"} local stats = {started = os.clock(), taken = 0, lost = 0, placed = 0, hatched = 0, sold = 0, bought = 0, rebirths = 0, candy = 0, candyEggs = 0, best = nil, bestValue = 0, cashStart = nil} local logLines = {} local lastLog, lastLogAt = nil, 0 local function log(msg) if msg == lastLog and os.clock() - lastLogAt < 60 then return end lastLog, lastLogAt = msg, os.clock() table.insert(logLines, 1, os.date("%H:%M:%S") .. " " .. msg) if #logLines > 80 then table.remove(logLines) end end local function data(key) if not Data then return nil end local okd, v = pcall(Data.GetValue, Data, key) if okd then return v end end local function count(t) local n = 0 if type(t) == "table" then for _ in pairs(t) do n = n + 1 end end return n end local SUFFIX = {"", "K", "M", "B", "T", "Qa", "Qi", "Sx", "Sp", "Oc", "No", "Dc"} local function short(n) n = tonumber(n) or 0 local i = 1 while math.abs(n) >= 1000 and i < #SUFFIX do n = n / 1000 i = i + 1 end if i == 1 then return tostring(math.floor(n + 0.5)) end return (string.format("%.2f", n):gsub("%.?0+$", "")) .. SUFFIX[i] end local function call(service, method, ...) local s = svc[service] if not s or type(s[method]) ~= "function" then return nil, service .. "." .. method .. " is missing" end local args = table.pack(...) local okc, done, res = pcall(function() return s[method](s, table.unpack(args, 1, args.n)):await() end) if not okc then return nil, tostring(done) end if not done then return nil, tostring(res) end return res end local function reasonOf(res, err) if type(res) == "table" and res.Reason then return tostring(res.Reason) end return tostring(err or "refused") end local variantMult = {} for _, v in pairs(eggConfig.Variants or {}) do if type(v) == "table" and v.Name then variantMult[v.Name] = tonumber(v.CashMultiplier) or 1 end end local function animalFor(eggName) local e = eggConfig.Eggs and eggConfig.Eggs[eggName] return (e and e.Animal) or eggName end local function animalValue(name, variant) local a = animalConfig[name] local cps = a and tonumber(a.CashPerSecond) or 0 return cps * (variantMult[variant or "Normal"] or 1) end local function rarityOf(eggName) local e = eggConfig.Eggs and eggConfig.Eggs[eggName] return (e and e.Rarity) or "?" end local function eggLabel(eggName, variant) local name = tostring(eggName) if variant and variant ~= "Normal" then name = variant .. " " .. name end return name .. " (" .. rarityOf(eggName) .. ")" end local function animals() local inv, eq = data("Inventory") or {}, data("EquippedAnimals") or {} local list = {} for key, item in pairs(inv) do if type(item) == "table" and item.Handler == "Animal" then local variant = (type(item.CustomData) == "table" and item.CustomData.Variant) or item.Variant or "Normal" table.insert(list, {key = key, name = item.Name, variant = variant, value = animalValue(item.Name, variant), equipped = eq[key] ~= nil}) end end return list end local function worstOnBase() local maxAnimals = tonumber(data("MaxAnimals")) or 7 local n, worst = 0, math.huge for _, a in ipairs(animals()) do if a.equipped then n = n + 1 worst = math.min(worst, a.value) end end if n < maxAnimals then return 0 end return worst end local function getChar() local c = plr.Character if not c then return nil end local h = c:FindFirstChildOfClass("Humanoid") local r = c:FindFirstChild("HumanoidRootPart") if h and r and h.Health > 0 then return c, h, r end return nil end local function flat(v) return Vector3.new(v.X, 0, v.Z) end local function steer(dir) dir = flat(dir) if dir.Magnitude < 0.001 then pcall(function() MoveAction:Fire(Vector2.zero) end) return end dir = dir.Unit local cam = workspace.CurrentCamera local look = flat(cam.CFrame.LookVector) local right = flat(cam.CFrame.RightVector) if look.Magnitude < 0.001 or right.Magnitude < 0.001 then look, right = Vector3.new(0, 0, -1), Vector3.new(1, 0, 0) end look, right = look.Unit, right.Unit local x, y = dir:Dot(right), dir:Dot(look) pcall(function() MoveAction:Fire(Vector2.new(x, y)) end) end local function hold(x, y) pcall(function() MoveAction:Fire(Vector2.new(x, y)) end) end local function stopMoving() pcall(function() MoveAction:Fire(Vector2.zero) end) end local function tapJump() pcall(function() JumpAction:Fire(true) end) task.wait(0.1) pcall(function() JumpAction:Fire(false) end) end local function running(id) return alive and farm.enabled and farm.run == id end local function status(s) farm.status = s end local function walkTo(id, point, radius, limit) radius = radius or 2.5 limit = limit or 20 local started, lastPos, lastMove = os.clock(), nil, os.clock() while running(id) do local c, h, r = getChar() if not c then stopMoving() return false, "died" end local gap = flat(point - r.Position) if gap.Magnitude <= radius then stopMoving() return true end if h:GetState() == Enum.HumanoidStateType.Climbing then stopMoving() return false, "grabbed the wall" end if os.clock() - started > limit then stopMoving() return false, "took too long" end steer(gap) if not lastPos or (r.Position - lastPos).Magnitude > 1.5 then lastPos, lastMove = r.Position, os.clock() elseif os.clock() - lastMove > 1.2 then tapJump() lastMove = os.clock() end RunService.Heartbeat:Wait() end stopMoving() return false, "stopped" end local function myBase() if not Bases then return nil end local okb, b = pcall(Bases.GetBase, Bases) if okb then return b end end local function plotBox() local b = myBase() local fences = b and b:FindFirstChild("Fences") if not fences then return nil end local okp, cf, size = pcall(function() return fences:GetBoundingBox() end) if okp then return cf, size end end local function insidePlot(pos) local cf, size = plotBox() if not cf then return false end local p = cf:PointToObjectSpace(pos) return math.abs(p.X) < size.X / 2 + 1 and math.abs(p.Z) < size.Z / 2 + 1 end local function gatePoints() local b = myBase() local gate = b and b:FindFirstChild("Gate") local cf = plotBox() if not gate or not cf then return nil end local g = gate:GetPivot().Position local out = flat(g - cf.Position) if out.Magnitude < 0.1 then return nil end out = out.Unit return g - out * 5, g + out * 6 end local function travel(id, point, radius, limit) local c, _, r = getChar() if not c then return false, "died" end local fromInside, toInside = insidePlot(r.Position), insidePlot(point) if fromInside ~= toInside then local inner, outer = gatePoints() if inner then local first, second = outer, inner if fromInside then first, second = inner, outer end local okw, why = walkTo(id, first, 3, 15) if not okw and why ~= "took too long" then return false, why end okw, why = walkTo(id, second, 3, 10) if not okw and why ~= "took too long" then return false, why end end end return walkTo(id, point, radius, limit) end local function wallNear(folder, near, fallback) local minZ, maxZ, sumX, n, top = math.huge, -math.huge, 0, 0, -math.huge if folder then for _, d in ipairs(folder:GetDescendants()) do if d:IsA("TrussPart") and math.abs(d.Position.X - near.X) < 6 and math.abs(d.Position.Z - near.Z) < 60 then top = math.max(top, d.Position.Y + d.Size.Y / 2) if d.Position.Y < near.Y + 120 then minZ = math.min(minZ, d.Position.Z - d.Size.Z / 2) maxZ = math.max(maxZ, d.Position.Z + d.Size.Z / 2) sumX = sumX + d.Position.X n = n + 1 end end end end if n == 0 then return fallback.wallX, fallback.minZ, fallback.maxZ, math.huge end return sumX / n, minZ, maxZ, top end local towers = {} do local parts = workspace:FindFirstChild("TutorialParts") local padPart = parts and parts:FindFirstChild("Climb") local pad = padPart and padPart.Position or Vector3.new(2211.6, 74.3, -751.6) local wallX, minZ, maxZ, top = wallNear(workspace:FindFirstChild("Structures"), pad, {wallX = 2210.07, minZ = -774.1, maxZ = -726.1}) local nx = pad.X >= wallX and 1 or -1 towers.main = {name = "main", pad = pad, wallX = wallX, nx = nx, minZ = minZ, maxZ = maxZ, midZ = (minZ + maxZ) / 2, top = top} local dimension = workspace:FindFirstChild("HalloweenDimension") if dimension then local zones = getController("ZoneController") local start = zones and typeof(zones.DimensionLadderStart) == "Vector3" and zones.DimensionLadderStart or Vector3.new(2210.17, 73.74, 4553.02) local dx, dmin, dmax, dtop = wallNear(dimension, start, {wallX = 2210.17, minZ = 4526, maxZ = 4580}) towers.halloween = {name = "halloween", pad = Vector3.new(dx + nx * 1.5, start.Y, start.Z), wallX = dx, nx = nx, minZ = dmin, maxZ = dmax, midZ = (dmin + dmax) / 2, top = dtop} end end local tower = towers.main local function useWorld(name) tower = towers[name] or towers.main end local BIOMES = {} for name, z in pairs(zoneConfig) do if name ~= "Lobby" and type(z) == "table" and type(z.Height) == "number" then BIOMES[name] = {world = "main", height = z.Height} end end if towers.halloween then local islands = workspace.HalloweenDimension:FindFirstChild("Islands") for _, name in ipairs({"Pumpkin Abyss", "Bone Field", "Witches Castle"}) do local isl = islands and islands:FindFirstChild(name) local area = isl and isl:FindFirstChild("Area") if area and area:IsA("BasePart") then BIOMES[name] = {world = "halloween", height = area.Position.Y} end end end local function sidePoints(low) local z = low and (tower.minZ - 8) or (tower.maxZ + 8) local shaftZ = low and (tower.minZ + 6) or (tower.maxZ - 6) return { outer = Vector3.new(tower.wallX + tower.nx * 6, 0, z), corner = Vector3.new(tower.wallX - tower.nx * 4, 0, z), shaft = Vector3.new(tower.wallX + tower.nx * 14, 0, shaftZ), } end local floorCache = {} local function floorOf(biome) if floorCache[biome] then return floorCache[biome] end local info = BIOMES[biome] local t = info and towers[info.world] if not t then return nil end local params = RaycastParams.new() params.FilterType = Enum.RaycastFilterType.Exclude params.FilterDescendantsInstances = plr.Character and {plr.Character} or {} local origin = Vector3.new(t.wallX + t.nx * 3, info.height + 40, t.minZ - 8) for _ = 1, 10 do local hit = workspace:Raycast(origin, Vector3.new(0, -140, 0), params) if not hit then break end if hit.Instance:IsA("TrussPart") or not hit.Instance.CanCollide then origin = hit.Position - Vector3.new(0, 0.05, 0) else floorCache[biome] = hit.Position.Y return hit.Position.Y end end return nil end local gateLevel = {Forest = 0} for _, g in ipairs(staminaUpgradeConfig.BiomeGates or {}) do if type(g) == "table" and g.Name then gateLevel[g.Name] = tonumber(g.Level) or math.huge end end local portalConfig = require(config.Gameplay.portalConfig) local function halloweenOpen() if not towers.halloween or rs:GetAttribute(portalConfig.OpenAttribute or "HalloweenPortalOpen") ~= true then return false end local unlock = getController("HalloweenUnlockController") if unlock and type(unlock.IsUnlocked) == "function" then local oku, yes = pcall(unlock.IsUnlocked, unlock) if oku then return yes == true end end return (tonumber(data("Speed")) or 0) >= (tonumber(portalConfig.UnlockSpeed) or math.huge) end local function isTop(biome) local info = BIOMES[biome] local t = info and towers[info.world] local floor = floorOf(biome) return t ~= nil and floor ~= nil and t.top ~= nil and floor + 10 > t.top end local function topFloor(floorY) return tower.top ~= nil and floorY + 10 > tower.top end local function topDrop(from) return Vector3.new(tower.wallX + tower.nx * 6, 0, math.clamp(from.Z, tower.minZ + 4, tower.maxZ - 4)) end local function reachable(biome) local info = BIOMES[biome] if not info then return false end if settings.onlyWorld and info.world ~= settings.onlyWorld then return false end if settings.onlyBiome and biome ~= settings.onlyBiome then return false end if isTop(biome) and info.world ~= "main" then return false end local level = tonumber(data("StaminaLevel")) or 1 if info.world == "halloween" then if not settings.halloween or not halloweenOpen() then return false end local okh, reach = pcall(staminaUpgradeConfig.GetReachHeight, level) return okh and tonumber(reach) ~= nil and info.height <= reach end local need = gateLevel[biome] return need ~= nil and level >= need end local function worldAt(pos) if towers.halloween and math.abs(pos.Z - towers.halloween.pad.Z) < math.abs(pos.Z - towers.main.pad.Z) then return "halloween" end return "main" end local function currentWorld() local c = plr.Character local r = c and c:FindFirstChild("HumanoidRootPart") return r and worldAt(r.Position) or "main" end local function nightState() local t = workspace:GetServerTimeNow() local okn, isNight = pcall(dayCycle.IsNight, t) local okt, nightAt = pcall(dayCycle.GetNightStartsAt, t) local okd, dayAt = pcall(dayCycle.GetDayStartsAt, t) return okn and isNight == true, okt and (nightAt - t) or math.huge, okd and (dayAt - t) or 0 end local climbRatio = 0.7 local function climbWalkSpeed() local okw, ws = pcall(speedCurve.ToWalkSpeed, tonumber(data("Speed")) or 250) ws = okw and tonumber(ws) or 22 if Jetpack then local okj, m = pcall(Jetpack.GetSpeedMultiplier, Jetpack) if okj and tonumber(m) then ws = ws * m end end return math.max(ws, 1) end local function tripTime(biome) local info = BIOMES[biome] local t = towers[info and info.world or "main"] or towers.main local floor = floorOf(biome) or t.pad.Y local _, _, r = getChar() local walk = 8 if r then walk = worldAt(r.Position) == t.name and flat(t.pad - r.Position).Magnitude / 26 or 15 end local climb = math.max(0, floor + 8 - t.pad.Y - (staminaUpgradeConfig.ClimbBoostHeight or 125)) local fall = math.sqrt(2 * math.max(floor - t.pad.Y, 0) / workspace.Gravity) return walk + 2 + climb / (climbWalkSpeed() * climbRatio) + 16 + fall + 3 end local CHASE = tonumber(guardConfig.ChaseSpeed) or 18 local REPATH = tonumber(guardConfig.ChaseRepathInterval) or 0.2 local PATROL = 12 local BODY = 1.5 local function carrySpeed() local okc, v = pcall(function() return SpeedState.StateFunctions.Stealing() end) v = okc and tonumber(v) return (v and v > 0) and v or 10 end local function guardZone(biome) local okf, isl = pcall(guardGeometry.FindIsland, biome) local area = okf and isl and isl:FindFirstChild("Area") if area and area:IsA("BasePart") then return area end end local function guardsJailed() return workspace:GetServerTimeNow() < (tonumber(workspace:GetAttribute("GuardsJailedUntil")) or 0) end local reachCache = setmetatable({}, {__mode = "k"}) local function hitboxReach(box, pivot) if not box or not box.Parent then return 10 end if reachCache[box] then return reachCache[box] end local reach = 0 for _, sx in ipairs({-1, 1}) do for _, sz in ipairs({-1, 1}) do local corner = box.CFrame:PointToWorldSpace(Vector3.new(sx * box.Size.X / 2, 0, sz * box.Size.Z / 2)) reach = math.max(reach, flat(corner - pivot).Magnitude) end end reachCache[box] = reach return reach end local function guardsNear(floorY) local list = {} local now = os.clock() if GuardAi and type(GuardAi.Guards) == "table" then for _, g in pairs(GuardAi.Guards) do local okp, pos = pcall(function() return g.Pose.Value end) if okp and typeof(pos) == "Vector3" and g.Model and g.Model.Parent and math.abs(pos.Y - floorY) < 30 then local info = {pos = flat(pos), reach = hitboxReach(g.Hitbox, pos), state = g.State, left = (tonumber(g.NextAction) or now) - now} if g.State == "Walk" and typeof(g.FacingPosition) == "Vector3" then info.target = flat(g.FacingPosition) info.speed = (info.target - info.pos).Magnitude / math.max(info.left, 0.05) end table.insert(list, info) end end end local dimension = workspace:FindFirstChild("HalloweenDimension") local monsters = dimension and dimension:FindFirstChild("ActiveMiniMonsters") if monsters then local serverNow = workspace:GetServerTimeNow() for _, m in ipairs(monsters:GetChildren()) do local okp, cf = pcall(function() return m:GetPivot() end) if okp and m:IsA("Model") and math.abs(cf.Position.Y - floorY) < 30 and not m:GetAttribute("Boss") then local to, from = m:GetAttribute("MoveTo"), m:GetAttribute("MoveFrom") local duration = tonumber(m:GetAttribute("MoveDuration")) or 0 local info = {pos = flat(cf.Position), reach = 5, state = "Idle", left = 0, chase = 8} if typeof(to) == "Vector3" and typeof(from) == "Vector3" and duration > 0 then local speed = flat(to - from).Magnitude / duration info.state, info.target, info.speed = "Walk", flat(to), speed info.left = (tonumber(m:GetAttribute("MoveStart")) or serverNow) + duration - serverNow info.chase = math.max(speed, 8) end table.insert(list, info) end end end if GuardAi and type(GuardAi.Guards) == "table" then return list end local folder = workspace:FindFirstChild("LocalGuards") if not folder then return list end for _, m in ipairs(folder:GetChildren()) do local okp, cf = pcall(function() return m:GetPivot() end) if okp and math.abs(cf.Position.Y - floorY) < 30 then table.insert(list, {pos = flat(cf.Position), reach = hitboxReach(m:FindFirstChild("Hitbox", true), cf.Position), state = "?", left = 0}) end end return list end local function inZone(area, p) local q = area.CFrame:PointToObjectSpace(Vector3.new(p.X, area.Position.Y, p.Z)) return math.abs(q.X) <= area.Size.X / 2 and math.abs(q.Z) <= area.Size.Z / 2 end local function clampToZone(area, p) local q = area.CFrame:PointToObjectSpace(Vector3.new(p.X, area.Position.Y, p.Z)) local hx, hz = area.Size.X / 2, area.Size.Z / 2 local w = area.CFrame:PointToWorldSpace(Vector3.new(math.clamp(q.X, -hx, hx), 0, math.clamp(q.Z, -hz, hz))) return Vector3.new(w.X, 0, w.Z) end local function escapeRoute(from, low) local side = sidePoints(low) return {flat(from), side.corner, side.outer} end local function routeLength(route) local n = 0 for i = 2, #route do n = n + (route[i] - route[i - 1]).Magnitude end return n end local function closestApproach(route, area, guard, hold, startStay, endStay) local speed = carrySpeed() local me, g = route[1], guard.pos local seg, t, dt = 2, 0, 0.05 local nextRepath, target = hold, nil local walkFrom = hold + (startStay or 0) local stayUntil = nil local closest = (g - me).Magnitude - guard.reach - BODY for _ = 1, 1200 do t = t + dt if t <= hold then if guard.state == "Walk" and guard.target then if t < guard.left then local d = guard.target - g local step = guard.speed * dt if d.Magnitude <= step then g = guard.target else g = g + d.Unit * step end end elseif guard.state ~= "Idle" or t >= guard.left then local d = me - g if d.Magnitude > 0.5 then g = g + d.Unit * math.min(PATROL * dt, d.Magnitude) end end else local move = t > walkFrom and speed * dt or 0 while move > 0 and seg <= #route do local d = route[seg] - me if d.Magnitude <= move then me = route[seg] move = move - d.Magnitude seg = seg + 1 else me = me + d.Unit * move move = 0 end end if not inZone(area, me) then return closest end if seg > #route then stayUntil = stayUntil or (t + (endStay or 0)) if t >= stayUntil then return closest end end if t >= nextRepath then target = clampToZone(area, me) nextRepath = t + REPATH end local d = target - g local step = (guard.chase or CHASE) * dt if d.Magnitude <= step then g = target else g = g + d.Unit * step end closest = math.min(closest, (g - me).Magnitude - guard.reach - BODY) end end return closest end local function backFacePoint(pos) return Vector3.new(tower.wallX - tower.nx * 2.3, 0, math.clamp(pos.Z, tower.minZ + 2, tower.maxZ - 2)) end local function wallClimbTime() return 0.5 + 20 / math.max(climbWalkSpeed() * climbRatio, 8) end local REACT = 0.15 local function escapePlan(from, biome, floorY, hold) local area = guardZone(biome) local guards = (area and not guardsJailed()) and guardsNear(floorY) or {} local options = {} local top = isTop(biome) if top then local route = {flat(from), topDrop(from)} table.insert(options, {route = route, top = true, length = routeLength(route), stay = 0.5}) end if not top and settings.escape ~= "Up the wall" then for _, low in ipairs({true, false}) do local route = escapeRoute(from, low) table.insert(options, {route = route, low = low, length = routeLength(route)}) end end if not top and settings.escape ~= "Round the wall" then local route = {flat(from), backFacePoint(from)} table.insert(options, {route = route, wall = true, length = routeLength(route), stay = wallClimbTime()}) end local best for _, plan in ipairs(options) do plan.margin = math.huge for _, g in ipairs(guards) do plan.margin = math.min(plan.margin, closestApproach(plan.route, area, g, hold, REACT, plan.stay)) end if not best or plan.margin > best.margin or (plan.margin == best.margin and plan.length < best.length) then best = plan end end return best.margin > settings.guardMargin, best end local function dropPlan(biome, floorY) local area = guardZone(biome) local guards = (area and not guardsJailed()) and guardsNear(floorY) or {} local best for _, low in ipairs({true, false}) do local land = Vector3.new(tower.wallX - tower.nx * 1.5, 0, low and (tower.minZ - 1.5) or (tower.maxZ + 1.5)) local route = {land, sidePoints(low).outer} local margin = math.huge for _, g in ipairs(guards) do margin = math.min(margin, closestApproach(route, area, g, 0, 0.6, 0)) end if not best or margin > best.margin then best = {low = low, margin = margin} end end return best.margin > settings.guardMargin + 2, best end local function escapeLength(pos) return math.min(routeLength(escapeRoute(pos, true)), routeLength(escapeRoute(pos, false))) end local function eggsIn(biome) local folder = workspace:FindFirstChild("SpawnedEggs") folder = folder and folder:FindFirstChild(biome) local list = {} local info = BIOMES[biome] if not folder or not info then return list end local current = tower tower = towers[info.world] or towers.main local top = isTop(biome) for _, m in ipairs(folder:GetChildren()) do local eggName = m:GetAttribute("EggName") local prompt = eggName and m:FindFirstChildWhichIsA("ProximityPrompt", true) if prompt and prompt.Enabled then local variant = m:GetAttribute("Variant") or "Normal" local pos = m:GetPivot().Position table.insert(list, {model = m, prompt = prompt, biome = biome, name = eggName, variant = variant, value = animalValue(animalFor(eggName), variant), pos = pos, escape = top and flat(topDrop(pos) - pos).Magnitude or escapeLength(pos)}) end end tower = current return list end local biomeRest = {} local function bestEgg(onlyBiome, anyTime, skipModels) local least = settings.betterOnly and worstOnBase() or -1 local isNight, toNight = nightState() local timeCheck = settings.nights and not anyTime local best, nightBlocked = nil, false for biome in pairs(BIOMES) do local resting = not onlyBiome and os.clock() < (biomeRest[biome] or 0) if (not onlyBiome or biome == onlyBiome) and not resting and reachable(biome) and floorOf(biome) then local trip = tripTime(biome) + (settings.waitForGuard and 6 or 0) local tooLate = timeCheck and (isNight or trip + 4 > toNight) for _, e in ipairs(eggsIn(biome)) do local skip = e.value <= least or (skipModels ~= nil and skipModels[e.model] == true) if settings.waitForGuard and e.escape > settings.maxEscape then skip = true end if not skip and tooLate then skip = true nightBlocked = true end if not skip then e.trip = trip + (settings.waitForGuard and math.max(0, e.escape - 35) * 0.8 or 0) if settings.pick == "Most cash per minute" then e.score = e.value / trip else e.score = e.value end if not best or e.score > best.score or (e.score == best.score and trip < best.trip) then best = e end end end end end return best, nightBlocked end local function eggsOwned() local n = count(data("PlacedEggs")) for _, item in pairs(data("Inventory") or {}) do if type(item) == "table" and item.Handler == "Egg" then n = n + 1 end end return n end local lastStun, lastCaught = 0, 0 local function dropReason() if os.clock() - lastStun < 6 then return "a guard caught you" end if os.clock() - lastCaught < 6 then return "caught at night" end return "dropped it" end local function carrying() return plr:GetAttribute("CarryingEgg") ~= nil end local function onTreadmill() return Treadmill ~= nil and Treadmill.OnTreadmill == true end local function treadmillPart() local b = myBase() local folder = b and b:FindFirstChild("Treadmill") local m = folder and folder:FindFirstChildWhichIsA("Model") return m and (m.PrimaryPart or m:FindFirstChildWhichIsA("BasePart", true)) end local function leaveTreadmill() if onTreadmill() then pcall(function() Treadmill:DeactivateTreadmill() end) task.wait(0.4) end end local function goToWorld(id, world) if currentWorld() == world then useWorld(world) return true end leaveTreadmill() local dimension = workspace:FindFirstChild("HalloweenDimension") local portals = dimension and dimension:FindFirstChild("Portals") local route = world == "halloween" and "LobbyToHalloween" or "HalloweenToLobby" local model = portals and portals:FindFirstChild(route) local trigger = model and model:FindFirstChild("Trigger") if not trigger then return false, "couldn't find the portal" end status(world == "halloween" and "walking into the halloween portal" or "walking back through the portal") local front = model:FindFirstChild("OutPos") if front and front:IsA("BasePart") then travel(id, front.Position, 3, 40) else travel(id, trigger.Position, 2, 40) end local t = os.clock() while running(id) and currentWorld() ~= world and os.clock() - t < 12 do local c, _, r = getChar() if c then steer(trigger.Position - r.Position) end RunService.Heartbeat:Wait() end stopMoving() if currentWorld() ~= world then return false, "the portal didn't take you through" end useWorld(world) task.wait(1.5) return true end local function train(id, done) local part = treadmillPart() if not part then return false, "no treadmill yet" end if not onTreadmill() then local home, why = goToWorld(id, "main") if not home then return false, why end status("walking to the treadmill") travel(id, part.Position, 1.5, 30) local t = os.clock() while running(id) and not onTreadmill() and os.clock() - t < 3 do local c, _, r = getChar() if c then steer(part.Position - r.Position) end RunService.Heartbeat:Wait() end stopMoving() if not onTreadmill() then return false, "couldn't get on the treadmill" end log("training on the treadmill") end while running(id) and onTreadmill() and not done() do status("training speed (" .. short(data("Speed")) .. ")") task.wait(0.5) end return true end local function faceWall(r) local n = Vector3.new(tower.nx, 0, 0) local p = r.Position workspace.CurrentCamera.CFrame = CFrame.lookAt(p + n * 12 + Vector3.new(0, 3, 0), p - n * 4) end local function climbTo(id, height) local okw, why = travel(id, tower.pad, 3, 30) if not okw and why ~= "grabbed the wall" then return false, why end local started = os.clock() while running(id) do local c, h = getChar() if not c then return false, "died" end if h:GetState() == Enum.HumanoidStateType.Climbing then break end if os.clock() - started > 6 then stopMoving() return false, "couldn't grab the wall" end steer(Vector3.new(-tower.nx, 0, 0)) RunService.Heartbeat:Wait() end local lastY, lastProgress, offWallSince = nil, os.clock(), nil local measureFrom, measureAt = nil, nil while running(id) do local c, h, r = getChar() if not c then stopMoving() return false, "died" end local y = r.Position.Y if y >= height then stopMoving() if measureFrom and os.clock() - measureAt > 1 then local rate = (y - measureFrom) / (os.clock() - measureAt) climbRatio = math.clamp(rate / climbWalkSpeed(), 0.2, 1.5) end return true end if h:GetState() ~= Enum.HumanoidStateType.Climbing then offWallSince = offWallSince or os.clock() if os.clock() - offWallSince > 1 then stopMoving() return false, "fell off the wall" end else offWallSince = nil end if not measureFrom and y > tower.pad.Y + (staminaUpgradeConfig.ClimbBoostHeight or 125) + 10 then measureFrom, measureAt = y, os.clock() end faceWall(r) hold(0, 1) if not lastY or y > lastY + 0.5 then lastY, lastProgress = y, os.clock() elseif os.clock() - lastProgress > 4 then stopMoving() return false, "stuck on the wall" end status(string.format("climbing, %d / %d", math.floor(y), math.floor(height))) RunService.Heartbeat:Wait() end stopMoving() return false, "stopped" end local function stepOff(id, floorY) for _, dir in ipairs({1, -1}) do local started = os.clock() while running(id) do local c, h = getChar() if not c or h:GetState() ~= Enum.HumanoidStateType.Climbing then break end if os.clock() - started > 7 then break end hold(dir, 0) RunService.Heartbeat:Wait() end stopMoving() local c, h = getChar() if not c or h:GetState() ~= Enum.HumanoidStateType.Climbing then break end end local started = os.clock() while running(id) do local c, h, r = getChar() if not c then return false end if h.FloorMaterial ~= Enum.Material.Air and h:GetState() ~= Enum.HumanoidStateType.Climbing then return math.abs(r.Position.Y - floorY) < 9, r end if os.clock() - started > 5 then return false end RunService.Heartbeat:Wait() end return false end local function climbOver(id, floorY) local started = os.clock() while running(id) do local c, h, r = getChar() if not c then break end if h:GetState() ~= Enum.HumanoidStateType.Climbing and h.FloorMaterial ~= Enum.Material.Air and r.Position.Y > floorY - 1 then stopMoving() return true end if os.clock() - started > 8 then break end faceWall(r) hold(0, 1) RunService.Heartbeat:Wait() end stopMoving() return false end local function islandWalk(id, point, floorY, radius, limit) for _ = 1, 3 do local okw, why = walkTo(id, point, radius, limit) if okw or why ~= "grabbed the wall" then return okw, why end tapJump() local t = os.clock() while running(id) and os.clock() - t < 3 do local c, h = getChar() if not c then return false, "died" end if h.FloorMaterial ~= Enum.Material.Air and h:GetState() ~= Enum.HumanoidStateType.Climbing then break end RunService.Heartbeat:Wait() end local c, _, r = getChar() if not c or r.Position.Y < floorY - 6 then return false, "fell off the island" end end return false, "kept grabbing the wall" end local function dropDown(id, floorY, low) local side = sidePoints(low) local c, _, r = getChar() local drop = side.shaft if c and topFloor(floorY) then drop = topDrop(r.Position) islandWalk(id, Vector3.new(tower.wallX - tower.nx * 3, 0, drop.Z), floorY, 2.5, 15) else if c and tower.nx * (r.Position.X - tower.wallX) < 0 then islandWalk(id, side.corner, floorY, 2.5, 12) end islandWalk(id, side.outer, floorY, 3, 8) end local t = os.clock() while running(id) do local c, _, r = getChar() if not c then return false, "died" end if r.Position.Y < floorY - 8 then break end if os.clock() - t > 8 then stopMoving() return false, "couldn't find the drop" end steer(drop - r.Position) RunService.Heartbeat:Wait() end stopMoving() local limit = math.sqrt(2 * math.max(floorY - tower.pad.Y, 0) / workspace.Gravity) + 8 t = os.clock() while running(id) do local c, h, r = getChar() if not c then return false, "died" end if r.Position.Y < tower.pad.Y + 30 and h.FloorMaterial ~= Enum.Material.Air then return true end if os.clock() - t > limit then return false, "still falling" end RunService.Heartbeat:Wait() end return false, "stopped" end local function getDown(id) useWorld(currentWorld()) local function islandFloor(y) local nearestY for biome, info in pairs(BIOMES) do local f = info.world == tower.name and floorOf(biome) if f and math.abs(f - y) < 15 and (not nearestY or math.abs(f - y) < math.abs(nearestY - y)) then nearestY = f end end return nearestY end for _ = 1, 3 do local c, h, r = getChar() if not c then return false, "died" end local climbing = h:GetState() == Enum.HumanoidStateType.Climbing local floorY = islandFloor(r.Position.Y) if not climbing and not floorY and r.Position.Y < tower.pad.Y + 120 then return true end status("getting back down to the lobby") if climbing or not floorY then tapJump() else dropDown(id, floorY, r.Position.Z < tower.midZ) end local t = os.clock() while running(id) and os.clock() - t < 12 do local c2, h2 = getChar() if not c2 then return false, "died" end if h2.FloorMaterial ~= Enum.Material.Air and h2:GetState() ~= Enum.HumanoidStateType.Climbing then break end RunService.Heartbeat:Wait() end if not running(id) then return false, "stopped" end end local _, _, r = getChar() if not r then return false, "died" end return islandFloor(r.Position.Y) == nil, "stuck up on an island" end local function wallEscape(id, biome, floorY, plan) local n = Vector3.new(tower.nx, 0, 0) local function faceBack(r) workspace.CurrentCamera.CFrame = CFrame.lookAt(r.Position - n * 12 + Vector3.new(0, 3, 0), r.Position + n * 4) end local spot = plan.route[2] local t = os.clock() while running(id) do local c, h, r = getChar() if not c then return false, "died" end if h:GetState() == Enum.HumanoidStateType.Climbing then break end if os.clock() - t > 8 then log("couldn't get onto the back of the wall, running for it") return dropDown(id, floorY, r.Position.Z < tower.midZ) end local to = flat(spot - r.Position) if to.Magnitude > 1.5 then steer(to) else steer(n) end RunService.Heartbeat:Wait() end t = os.clock() while running(id) do local c, h, r = getChar() if not c then return false, "died" end if h:GetState() ~= Enum.HumanoidStateType.Climbing then stopMoving() return dropDown(id, floorY, r.Position.Z < tower.midZ) end if r.Position.Y >= floorY + 30 or os.clock() - t > 6 then break end faceBack(r) hold(0, 1) RunService.Heartbeat:Wait() end stopMoving() if not carrying() then return false, "lost it before getting up the wall" end local deadline = os.clock() + 90 local choice while running(id) do local c, h = getChar() if not c then return false, "died" end if h:GetState() ~= Enum.HumanoidStateType.Climbing then break end local clear clear, choice = dropPlan(biome, floorY) local isNight, toNight = nightState() if clear or os.clock() > deadline or (settings.nights and (isNight or toNight < 8)) then break end status("on the wall with the egg, waiting for the guard to move off") hold(0, 0) task.wait(0.15) end local low = choice == nil or choice.low local dir = (low and -1 or 1) * tower.nx t = os.clock() while running(id) do local c, h, r = getChar() if not c then return false, "died" end if h:GetState() ~= Enum.HumanoidStateType.Climbing or os.clock() - t > 8 then break end faceBack(r) hold(dir, 0) RunService.Heartbeat:Wait() end stopMoving() t = os.clock() while running(id) do local c, h = getChar() if not c then return false, "died" end if h.FloorMaterial ~= Enum.Material.Air or os.clock() - t > 4 then break end RunService.Heartbeat:Wait() end return dropDown(id, floorY, low) end local function grab(egg) for _ = 1, 2 do if not egg.model.Parent or not egg.prompt.Enabled then return false, "someone else took it" end pcall(function() egg.prompt:InputHoldBegin() end) task.wait((tonumber(egg.prompt.HoldDuration) or 0.5) + 0.15) pcall(function() egg.prompt:InputHoldEnd() end) local t = os.clock() while os.clock() - t < 2 do if carrying() then return true end task.wait(0.05) end end return false, "the prompt didn't take" end local function waitAndGrab(id, target, biome, floorY, deadline) local hold = (tonumber(target.prompt.HoldDuration) or 0.5) + 0.25 local fall = math.sqrt(2 * math.max(floorY - tower.pad.Y, 0) / workspace.Gravity) while running(id) do if not target.model.Parent or not target.prompt.Enabled then return "taken" end local c, _, r = getChar() if not c then return "stop" end local safe, plan = escapePlan(r.Position, biome, floorY, hold) if safe or not settings.waitForGuard then if grab(target) then return "got", plan end return "taken" end if os.clock() > deadline then return "timeout" end if settings.nights then local isNight, toNight = nightState() if isNight or toNight < plan.length / carrySpeed() + fall + 6 then return "night" end end status(string.format("waiting for the guard to move off (%ds left)", math.max(0, math.ceil(deadline - os.clock())))) task.wait(0.15) end return "stop" end local function trip(id, egg) local biome = egg.biome local floorY = floorOf(biome) if not floorY then return false, "couldn't find the " .. biome .. " floor" end log("going for " .. eggLabel(egg.name, egg.variant) .. " in " .. biome) local there, why = getDown(id) if not there then return false, why end there, why = goToWorld(id, BIOMES[biome].world) if not there then return false, why end status("going to " .. biome .. " for " .. eggLabel(egg.name, egg.variant)) local top = isTop(biome) local okc okc, why = climbTo(id, top and floorY - 4 or floorY + 7.5) if not okc then return false, why end local low, okw if top then if not climbOver(id, floorY) then return false, "couldn't get over the top" end local _, _, r = getChar() if not r then return false, "died" end low = r.Position.Z < tower.midZ status("walking to the egg") else local landed, r = stepOff(id, floorY) if not landed then return false, "missed the platform" end low = r.Position.Z < tower.midZ local side = sidePoints(low) status("walking to the egg") okw, why = islandWalk(id, side.outer, floorY, 3, 8) if okw then okw, why = islandWalk(id, side.corner, floorY, 2.5, 10) end if not okw and why ~= "took too long" then return false, why end end local tried = {} local target = egg local deadline = os.clock() + settings.guardWait local before, plan, result = eggsOwned(), nil, nil while running(id) do if not target or not target.model.Parent or not target.prompt.Enabled then target = bestEgg(biome, true, tried) if not target then break end end local exitLow = routeLength(escapeRoute(target.pos, true)) <= routeLength(escapeRoute(target.pos, false)) local toward = flat((top and topDrop(target.pos) or sidePoints(exitLow).corner) - target.pos) local spot = toward.Magnitude > 0.1 and (flat(target.pos) + toward.Unit * 5) or target.pos okw, why = islandWalk(id, spot, floorY, 2, 15) local _, _, here = getChar() local close = here ~= nil and flat(target.pos - here.Position).Magnitude <= 6 if not okw and not close then if why == "stopped" or why == "died" or why == "fell off the island" then return false, why end tried[target.model] = true target = nil else before = eggsOwned() result, plan = waitAndGrab(id, target, biome, floorY, deadline) if result == "got" or result == "stop" or result == "timeout" or result == "night" then break end tried[target.model] = true target = nil end end if result == "timeout" and running(id) then local least = settings.betterOnly and worstOnBase() or -1 local spare for _, e in ipairs(eggsIn(biome)) do if not tried[e.model] and (not target or e.model ~= target.model) and e.value > least then local safe, p = escapePlan(e.pos, biome, floorY, 2) if safe and p.margin > settings.guardMargin + 4 and (not spare or e.value > spare.value) then spare = e end end end if spare then log("switching to " .. eggLabel(spare.name, spare.variant) .. ", the guard is away from it") if islandWalk(id, spare.pos, floorY, 4, 10) then target = spare before = eggsOwned() result, plan = waitAndGrab(id, spare, biome, floorY, os.clock() + 8) end end end if result == "stop" or not running(id) then return false, "stopped" end if result ~= "got" then if result == "timeout" then biomeRest[biome] = os.clock() + 60 log("the " .. biome .. " guard never gave an opening, trying elsewhere for a minute") end local c2, _, r2 = getChar() dropDown(id, floorY, c2 and r2.Position.Z < tower.midZ or low) if result == "night" then return false, "night is close" end return false, "no safe moment to grab" end status("bringing back " .. eggLabel(target.name, target.variant)) local okd if plan.wall then log("running for the back of the wall with it") okd, why = wallEscape(id, biome, floorY, plan) else okd, why = dropDown(id, floorY, plan.low) end if not okd then if not carrying() then stats.lost = stats.lost + 1 log("lost the egg: " .. dropReason()) end return false, why end local t = os.clock() while carrying() and os.clock() - t < 6 do task.wait(0.1) end task.wait(0.5) if eggsOwned() > before then stats.taken = stats.taken + 1 if target.value > stats.bestValue then stats.best, stats.bestValue = eggLabel(target.name, target.variant), target.value end log("got " .. eggLabel(target.name, target.variant) .. ", worth " .. short(target.value) .. "/s") return true end stats.lost = stats.lost + 1 log("lost the egg: " .. dropReason()) return false, "egg lost" end local CANDY_ISLAND = "Pumpkin Abyss" local BAT_REACH = 5 local function batTool() local c = plr.Character local bp = plr:FindFirstChildOfClass("Backpack") return (c and c:FindFirstChild("Bat")) or (bp and bp:FindFirstChild("Bat")) end local function putAwayBat() local _, h = getChar() local c = plr.Character if h and c and c:FindFirstChild("Bat") then pcall(function() h:UnequipTools() end) end end local function monsterPos(m, serverNow) local from, to = m:GetAttribute("MoveFrom"), m:GetAttribute("MoveTo") local duration = tonumber(m:GetAttribute("MoveDuration")) or 0 if typeof(from) == "Vector3" and typeof(to) == "Vector3" and duration > 0 then local a = math.clamp((serverNow - (tonumber(m:GetAttribute("MoveStart")) or serverNow)) / duration, 0, 1) return from:Lerp(to, a) end return m:GetPivot().Position end local function nearestMonster(from) local dimension = workspace:FindFirstChild("HalloweenDimension") local folder = dimension and dimension:FindFirstChild("ActiveMiniMonsters") if not folder then return nil end local serverNow = workspace:GetServerTimeNow() local best, bestPos, bestGap for _, m in ipairs(folder:GetChildren()) do if m:IsA("Model") and m:GetAttribute("Island") == CANDY_ISLAND and not m:GetAttribute("Boss") and not m:GetAttribute("Dying") and not m:GetAttribute("Dead") and (tonumber(m:GetAttribute("Health")) or 0) > 0 then local pos = monsterPos(m, serverNow) local gap = flat(pos - from).Magnitude if not bestGap or gap < bestGap then best, bestPos, bestGap = m, pos, gap end end end return best, bestPos, bestGap end local function nearestCandy(from, floorY) local folder = workspace:FindFirstChild("CandyDrops") if not folder then return nil end local best, bestGap for _, part in ipairs(folder:GetChildren()) do if part:IsA("BasePart") and math.abs(part.Position.Y - floorY) < 15 then local gap = flat(part.Position - from).Magnitude if gap < 60 and (not bestGap or gap < bestGap) then best, bestGap = part, gap end end end return best end local function playerNear(pos, radius) for _, other in ipairs(Players:GetPlayers()) do local r = other ~= plr and other.Character and other.Character:FindFirstChild("HumanoidRootPart") if r and (r.Position - pos).Magnitude < radius then return true end end return false end local function farmCandy(id, done) if not halloweenOpen() then return false, "the event portal is closed" end if not BIOMES[CANDY_ISLAND] then return false, "couldn't find " .. CANDY_ISLAND end if not batTool() then return false, "no bat" end local floorY = floorOf(CANDY_ISLAND) if not floorY then return false, "couldn't find the " .. CANDY_ISLAND .. " floor" end local c, h, r = getChar() if not c then return false, "died" end if currentWorld() ~= "halloween" or math.abs(r.Position.Y - floorY) > 8 then leaveTreadmill() local ok, why = getDown(id) if not ok then return false, why end ok, why = goToWorld(id, "halloween") if not ok then return false, why end status("going to " .. CANDY_ISLAND .. " for candy") ok, why = climbTo(id, floorY + 7.5) if not ok then return false, why end local landed, r2 = stepOff(id, floorY) if not landed then return false, "missed the platform" end local side = sidePoints(r2.Position.Z < tower.midZ) islandWalk(id, side.outer, floorY, 3, 8) islandWalk(id, side.corner, floorY, 2.5, 10) log("hitting monsters on " .. CANDY_ISLAND .. " for candy") end local lastCandy = tonumber(data("Candy")) or 0 local nextCheck, nextSwing = 0, 0 while running(id) do if os.clock() >= nextCheck then if done() then break end nextCheck = os.clock() + 2 end c, h, r = getChar() if not c then return false, "died" end if math.abs(r.Position.Y - floorY) > 10 then return false, "fell off the island" end if h.Health < h.MaxHealth * 0.35 then putAwayBat() log("health low, leaving the candy island") dropDown(id, floorY, r.Position.Z < tower.midZ) return false, "health low" end local candy = tonumber(data("Candy")) or 0 if candy > lastCandy then stats.candy = stats.candy + (candy - lastCandy) end lastCandy = candy local drop = nearestCandy(r.Position, floorY) local monster, pos, gap = nearestMonster(r.Position) if drop and (not monster or gap > BAT_REACH) then status("picking up candy (" .. short(candy) .. ")") steer(drop.Position - r.Position) elseif not monster then stopMoving() status("waiting for a monster (" .. short(candy) .. " candy)") else status(string.format("hitting a %s (%s candy)", tostring(monster:GetAttribute("MonsterName") or monster.Name), short(candy))) if gap > 2.5 then steer(pos - r.Position) else stopMoving() end if gap <= BAT_REACH and os.clock() >= nextSwing and not playerNear(r.Position, 10) then local bat = batTool() if bat and bat.Parent ~= c then pcall(function() h:EquipTool(bat) end) end if bat and bat.Parent == c then pcall(function() bat:Activate() end) nextSwing = os.clock() + (tonumber(bat:GetAttribute("Cooldown")) or 0.35) + 0.05 + math.random() * 0.15 end end end RunService.Heartbeat:Wait() end stopMoving() putAwayBat() return true end local function buyCandyEggs() while alive and settings.candyEggs and (tonumber(data("Candy")) or 0) >= 250 do local ok, err = call("HalloweenShopService", "BuyCandyEgg") if ok ~= true then log("couldn't buy a candy egg" .. (err and (": " .. tostring(err)) or "")) return end stats.candyEggs = stats.candyEggs + 1 log("bought a Halloween Dimension Egg with candy") task.wait(1) end end local function nextEgg() if settings.trainOnly then return nil, "training only" end local egg, nightBlocked = bestEgg() if egg then return egg end if nightBlocked then local isNight = nightState() return nil, isNight and "night time" or "night is close" end return nil, "no eggs worth taking" end local function farmLoop(id) log("auto farm on") while running(id) do local c, _, r = getChar() if not c then status("waiting to respawn") task.wait(1) elseif flat(r.Position - towers[worldAt(r.Position)].pad).Magnitude > 1500 then status("away from both towers (a boss fight?), waiting") task.wait(2) elseif carrying() then useWorld(worldAt(r.Position)) if r.Position.Y < tower.pad.Y + 30 then status("waiting for the egg to be claimed") task.wait(1) else local nearest, nearestY for biome, info in pairs(BIOMES) do local y = info.world == tower.name and floorOf(biome) if y and (not nearestY or math.abs(y - r.Position.Y) < math.abs(nearestY - r.Position.Y)) then nearest, nearestY = biome, y end end if nearestY and math.abs(nearestY - r.Position.Y) < 15 then dropDown(id, nearestY, r.Position.Z < tower.midZ) else tapJump() task.wait(1) end end else local egg, why = nextEgg() if egg then leaveTreadmill() local okt, res = trip(id, egg) if not okt and running(id) then log("trip cut short: " .. tostring(res)) task.wait(0.5) end else local trained = false local function eggReady() return nextEgg() ~= nil end if settings.idle == "Farm candy (Halloween)" and halloweenOpen() then local okc, res = farmCandy(id, eggReady) trained = okc if not okc and running(id) then log("candy farming stopped: " .. tostring(res)) task.wait(1) end elseif settings.idle == "Train on the treadmill" and treadmillPart() then if not onTreadmill() then getDown(id) end trained = train(id, eggReady) end if not trained then status("waiting: " .. why) task.wait(1) end end end RunService.Heartbeat:Wait() end stopMoving() end local function setFarm(on) on = on == true and alive if on == farm.enabled then return end farm.enabled = on farm.run = farm.run + 1 stopMoving() if on then local id = farm.run task.spawn(function() local okf, err = pcall(farmLoop, id) stopMoving() if not okf then log("farm error: " .. tostring(err)) warn("[climb eggs] " .. tostring(err)) end end) else farm.status = "off" log("auto farm off") end end local spotRefused = {} local placePause = 0 local function freeSpot() local cf, size = plotBox() local b = myBase() if not cf or not b then return nil end local taken = {} local placed = b:FindFirstChild("PlacedEggs") if placed then for _, e in ipairs(placed:GetChildren()) do local okp, p = pcall(function() return e:GetPivot().Position end) if okp then table.insert(taken, p) end end end local ground = workspace:FindFirstChild("Ground") local y = (ground and ground:IsA("BasePart")) and (ground.Position.Y + ground.Size.Y / 2) or cf.Position.Y local hx, hz = size.X / 2 - 5, size.Z / 2 - 5 local x = -hx while x <= hx do local z = -hz while z <= hz do local p = cf:PointToWorldSpace(Vector3.new(x, 0, z)) p = Vector3.new(p.X, y, p.Z) local key = math.floor(x) .. ":" .. math.floor(z) local clear = not spotRefused[key] or os.clock() - spotRefused[key] > 120 if clear then for _, t in ipairs(taken) do if flat(t - p).Magnitude < 6 then clear = false break end end end if clear then return CFrame.new(p), key end z = z + 6 end x = x + 6 end return nil end local function placeOne() if os.clock() < placePause then return false end local key for k, item in pairs(data("Inventory") or {}) do if type(item) == "table" and item.Handler == "Egg" then key = k break end end if not key then return false end local spot, spotKey = freeSpot() if not spot then log("no free spot on the plot for eggs") placePause = os.clock() + 20 return false end local res, err = call("EggPlacementService", "RequestToPlace", key, spot) if res and res.Status then stats.placed = stats.placed + 1 log("placed a " .. key:split("_")[1] .. " egg") return true end spotRefused[spotKey] = os.clock() log("couldn't place an egg: " .. reasonOf(res, err)) placePause = os.clock() + 8 return false end local needEquip, lastEquip = false, 0 local function hatchOne() if not Hatcher then return false end local okc, can = pcall(backpackLimits.CanHatch, data("Inventory")) if okc and not can then return false end for key, info in pairs(data("PlacedEggs") or {}) do if type(info) == "table" and info.CanHatch and not (Hatcher.Pending and Hatcher.Pending[key]) then pcall(function() Hatcher:Hatch(key) end) local t = os.clock() while (data("PlacedEggs") or {})[key] and os.clock() - t < 8 do task.wait(0.25) end if not (data("PlacedEggs") or {})[key] then stats.hatched = stats.hatched + 1 log("hatched a " .. key:split("_")[1]) needEquip = true end return true end end return false end local function equipBest() if not Loadout then return end local spare, onBase = 0, 0 for _, a in ipairs(animals()) do if a.equipped then onBase = onBase + 1 else spare = spare + 1 end end if spare == 0 then needEquip = false return end if needEquip or os.clock() - lastEquip > 45 then needEquip = false lastEquip = os.clock() pcall(function() Loadout:Request("EquipBest") end) end end local lastSell = 0 local function sellSpare() if os.clock() - lastSell < 15 then return end local spare = {} for _, a in ipairs(animals()) do if not a.equipped then table.insert(spare, a) end end local okf, full = pcall(backpackLimits.IsFull, data("Inventory")) full = okf and full == true if #spare <= settings.keepSpare and not full then return end lastSell = os.clock() table.sort(spare, function(a, b) return a.value < b.value end) local n = math.max(#spare - settings.keepSpare, 1) local keys = {} for i = 1, math.min(n, #spare) do table.insert(keys, spare[i].key) end local res, err = call("AnimalSellService", "Request", "SellList", keys) if res and res.Status then stats.sold = stats.sold + #keys log("sold " .. #keys .. " spare animal" .. (#keys == 1 and "" or "s") .. " for $" .. short(res.Amount)) else log("couldn't sell: " .. reasonOf(res, err)) end end local buyCooldown = {} local function upgradeOptions() local opts = {} if settings.buyStamina then local lvl = tonumber(data("StaminaLevel")) or 1 if lvl < (tonumber(staminaUpgradeConfig.MaxLevel) or 30) then local okp, price = pcall(staminaUpgradeConfig.GetPrice, lvl) local tut = data("Tutorial") if type(tut) == "table" and tut.FreeStaminaUsed == false then price = 0 end if okp and tonumber(price) then table.insert(opts, {what = "stamina", cost = tonumber(price), level = lvl}) end end end if settings.buyTreadmill then local lvl = tonumber(data("TreadmillLevel")) or 0 local nxt = treadmillConfig.LevelConfig and treadmillConfig.LevelConfig[lvl + 1] if nxt and lvl < (tonumber(treadmillConfig.MaxLevel) or 12) then table.insert(opts, {what = "treadmill", cost = tonumber(nxt.UpgradeCost) or 0, level = lvl}) end end if settings.buyBase then local lvl = tonumber(data("BaseLevel")) or 1 local nxt = baseUpgradeConfig.Levels and baseUpgradeConfig.Levels[lvl + 1] if nxt then table.insert(opts, {what = "base", cost = tonumber(nxt.UpgradeCost) or math.huge, level = lvl}) end end table.sort(opts, function(a, b) return a.cost < b.cost end) return opts end local NAMES = {stamina = "stamina", treadmill = "treadmill", base = "base slots"} local function buyUpgrades() local cash = tonumber(data("Cash")) or 0 local budget = cash * (1 - settings.reserve / 100) for _, opt in ipairs(upgradeOptions()) do if opt.cost <= budget and os.clock() > (buyCooldown[opt.what] or 0) then local res, err if opt.what == "stamina" then res, err = call("StaminaUpgradeService", "Purchase", opt.level) elseif opt.what == "treadmill" then res, err = call("TreadmillService", "RequestToUpgrade") else res, err = call("BaseUpgradeService", "RequestToUpgrade") end if res and res.Status then stats.bought = stats.bought + 1 log("bought " .. NAMES[opt.what] .. " level " .. (opt.level + 1) .. (opt.cost > 0 and (" for $" .. short(opt.cost)) or " (free)")) else buyCooldown[opt.what] = os.clock() + 30 log("couldn't buy " .. NAMES[opt.what] .. ": " .. reasonOf(res, err)) end return end end end local rebirthPause = 0 local function rebirthReady() local n = tonumber(data("Rebirths")) or 0 local maxR = tonumber(rebirthConfig.MaxRebirths) or 0 if maxR > 0 and n >= maxR then return false end local okr, req = pcall(rebirthConfig.GetRequirements, n) if not okr or type(req) ~= "table" then return false end for stat, need in pairs(req) do if (tonumber(data(stat)) or 0) < (tonumber(need) or math.huge) then return false end end return true end local function tryRebirth() if os.clock() < rebirthPause or not rebirthReady() then return end local res, err = call("RebirthService", "Request", false) if res and res.Status then stats.rebirths = stats.rebirths + 1 log("rebirthed (now " .. tostring(data("Rebirths")) .. ")") else rebirthPause = os.clock() + 60 log("couldn't rebirth: " .. reasonOf(res, err)) end end local lastDaily, lastIndex = -1e9, -1e9 local function claimRewards() if Gifts then for i = 1, 12 do local okr, ready = pcall(Gifts.IsReady, Gifts, i) local okc, claimed = pcall(Gifts.IsClaimed, Gifts, i) if okr and ready == true and okc and claimed ~= true then local res = call("GiftPlayTimeService", "Claim", i) if res and res.Status then log("claimed playtime gift " .. i) end task.wait(0.4) end end end if os.clock() - lastDaily > 600 then lastDaily = os.clock() local res = call("DailyRewardsService", "Claim") if res and res.Status then log("claimed the daily reward") end end if os.clock() - lastIndex > 300 then lastIndex = os.clock() local res = call("IndexService", "ClaimAll") if res and res.Status then log("claimed index rewards") end end if (tonumber(data("PendingOfflineCash")) or 0) > 0 then local res = call("CashFlowService", "ClaimOfflineCash") if res and res.Status then log("claimed offline cash") end end end task.spawn(function() while alive do pcall(function() if settings.hatch and hatchOne() then return end if settings.place then placeOne() end if settings.equip then equipBest() end if settings.sell then sellSpare() end end) task.wait(1.5) end end) task.spawn(function() local rounds = 0 while alive do rounds = rounds + 1 pcall(function() if settings.rebirth then tryRebirth() end if settings.buyStamina or settings.buyTreadmill or settings.buyBase then buyUpgrades() end if settings.rewards and rounds % 10 == 1 then claimRewards() end if settings.candyEggs and rounds % 5 == 2 then buyCandyEggs() end end) task.wait(2) end end) if svc.TreadmillService and svc.TreadmillService.ShowMultiplier then pcall(function() connect(svc.TreadmillService.ShowMultiplier, function(multId) if not alive or not settings.multipliers or not Treadmill then return end task.delay(0.35 + math.random() * 0.9, function() if alive and onTreadmill() then pcall(function() Treadmill:ClaimMultiplier(multId) end) end end) end) end) end if svc.DayCycleService and svc.DayCycleService.CaughtAtNight then pcall(function() connect(svc.DayCycleService.CaughtAtNight, function(caught) if caught then lastCaught = os.clock() end end) end) end local function watchCharacter(c) connect(c:GetAttributeChangedSignal("GuardStunned"), function() if c:GetAttribute("GuardStunned") then lastStun = os.clock() end end) end if plr.Character then watchCharacter(plr.Character) end connect(plr.CharacterAdded, watchCharacter) connect(plr.Idled, function() if not settings.antiAfk then return end pcall(function() VirtualUser:CaptureController() VirtualUser:ClickButton2(Vector2.new()) end) end) elevate() local function shutdown() if not alive then return end alive = false farm.enabled = false farm.run = farm.run + 1 stopMoving() for _, c in ipairs(conns) do pcall(function() c:Disconnect() end) end if genv.__CFAE_FARM and genv.__CFAE_FARM.Settings == settings then genv.__CFAE_FARM = nil end end local window = BPUI:CreateWindow({Version = "1.4.0", Title = "Climb Eggs", Subtitle = "Climb For Animals Eggs", Icon = "egg", Theme = "Void", ToggleKey = Enum.KeyCode.RightShift, ShowSettings = true, ConfigFolder = "CatnClimbEggs", Watermark = false, CloseBehavior = "Hide", OnDestroy = shutdown, }) genv.__CFAE_FARM = { Farm = farm, Settings = settings, Stats = stats, Log = logLines, SetFarm = setFarm, Debug = {EscapePlan = escapePlan, EggsIn = eggsIn, FloorOf = floorOf, NextEgg = nextEgg, IsTop = isTop, Reachable = reachable}, Destroy = function() shutdown() pcall(function() window:Destroy() end) end, } local ui = {} local farmTab = window:CreateTab({Name = "Farm", Icon = "egg"}) local main = farmTab:CreateSection("Auto farm") local farmToggle = main:AddToggle({Name = "Auto farm", Default = false, Flag = "cfae_farm", Description = "Climbs, takes the best egg you can reach, brings it back. Trains when there's nothing to take.", Callback = function(v) setFarm(v) end}) main:AddKeybind({Name = "Keybind", Default = Enum.KeyCode.F6, Mode = "Press", Flag = "cfae_farm_key", Callback = function() farmToggle:Set(not farm.enabled) end}) ui.status = main:AddLabel({Text = "off", Style = "Sub"}) ui.session = main:AddLabel({Text = "-", Style = "Sub"}) ui.account = main:AddLabel({Text = "-", Style = "Sub"}) local eggSec = farmTab:CreateSection("Eggs") eggSec:AddDropdown({Name = "Pick", Options = {"Most valuable", "Most cash per minute"}, Default = "Most valuable", Flag = "cfae_pick", Description = "Cash per minute weighs how long the climb takes.", Callback = function(v) settings.pick = v end}) local guardToggle = eggSec:AddToggle({Name = "Wait for the guard", Default = true, Flag = "cfae_guard_wait", Description = "Guards run at 18, you carry at 10. Waits by the egg until the guard is too far off to catch you before you're past the wall.", Callback = function(v) settings.waitForGuard = v == true end}) eggSec:AddDropdown({Name = "Escape route", DependsOn = guardToggle, Options = {"Best", "Round the wall", "Up the wall"}, Default = "Best", Flag = "cfae_escape", Description = "Up the wall: run for the back of the tower, climb out of the guard's reach, hop off once it's wandered away.", Callback = function(v) settings.escape = v end}) eggSec:AddSlider({Name = "Longest wait per trip", DependsOn = guardToggle, Min = 5, Max = 120, Default = 45, Increment = 5, Suffix = " s", Flag = "cfae_guard_wait_s", Description = "Then it takes any egg up there the guard is away from, or tries another biome for a minute.", Callback = function(v) settings.guardWait = math.clamp(tonumber(v) or 45, 5, 120) end}) eggSec:AddSlider({Name = "Safety margin", DependsOn = guardToggle, Min = 0, Max = 10, Default = 2, Increment = 1, Suffix = " studs", Flag = "cfae_guard_margin", Description = "Room left between the guard's hitbox and you on the way out. Higher waits longer but gets caught less.", Callback = function(v) settings.guardMargin = math.clamp(tonumber(v) or 2, 0, 10) end}) eggSec:AddToggle({Name = "Only eggs better than my worst animal", Default = false, Flag = "cfae_better", Description = "Once the base is full, skips eggs that wouldn't replace anything.", Callback = function(v) settings.betterOnly = v == true end}) eggSec:AddToggle({Name = "Halloween eggs", Default = true, Flag = "cfae_halloween", Description = "Also goes through the halloween portal for Pumpkin Abyss, Bone Field and Witches Castle eggs while the event is open.", Callback = function(v) settings.halloween = v == true end}) eggSec:AddToggle({Name = "Stay off the tower at night", Default = true, Flag = "cfae_nights", Description = "Anyone carrying an egg at night drops it. Waits for the restock instead.", Callback = function(v) settings.nights = v == true end}) ui.next = eggSec:AddLabel({Text = "next: -", Style = "Sub"}) ui.night = eggSec:AddLabel({Text = "-", Style = "Sub"}) local idleSec = farmTab:CreateSection("Between trips") idleSec:AddDropdown({Name = "When there's nothing to take", Options = {"Train on the treadmill", "Farm candy (Halloween)", "Wait in the lobby"}, Default = "Train on the treadmill", Flag = "cfae_idle", Description = "Farm candy hits the pumpkins on Pumpkin Abyss with your Bat while the event is open.", Callback = function(v) settings.idle = v end}) idleSec:AddToggle({Name = "Buy candy eggs", Default = true, Flag = "cfae_candy_eggs", Description = "Spends every 250 candy on a Halloween Dimension Egg.", Callback = function(v) settings.candyEggs = v == true end}) idleSec:AddToggle({Name = "Train only", Default = false, Flag = "cfae_train_only", Description = "No egg runs, just speed for rebirths.", Callback = function(v) settings.trainOnly = v == true end}) idleSec:AddToggle({Name = "Click speed multipliers", Default = true, Flag = "cfae_mult", Callback = function(v) settings.multipliers = v == true end}) local baseTab = window:CreateTab({Name = "Base", Icon = "house"}) local baseSec = baseTab:CreateSection("Eggs and animals") baseSec:AddToggle({Name = "Place eggs", Default = true, Flag = "cfae_place", Description = "Puts eggs from your backpack on free spots of your plot.", Callback = function(v) settings.place = v == true end}) baseSec:AddToggle({Name = "Hatch eggs", Default = true, Flag = "cfae_hatch", Callback = function(v) settings.hatch = v == true end}) baseSec:AddToggle({Name = "Equip best animals", Default = true, Flag = "cfae_equip", Description = "Uses the game's Equip Best after each hatch.", Callback = function(v) settings.equip = v == true end}) local sellToggle = baseSec:AddToggle({Name = "Sell spare animals", Default = false, Flag = "cfae_sell", Description = "Sells the weakest animals that aren't on your base. Animals on the base are never sold.", Callback = function(v) settings.sell = v == true end}) baseSec:AddSlider({Name = "Spare animals to keep", DependsOn = sellToggle, Min = 0, Max = 30, Default = 5, Increment = 1, Flag = "cfae_keep", Callback = function(v) settings.keepSpare = math.floor(tonumber(v) or 5) end}) ui.base = baseSec:AddLabel({Text = "-", Style = "Sub"}) local upTab = window:CreateTab({Name = "Upgrades", Icon = "trending-up"}) local upSec = upTab:CreateSection("Spending") upSec:AddToggle({Name = "Buy stamina", Default = true, Flag = "cfae_buy_stamina", Description = "More stamina opens higher biomes with better eggs.", Callback = function(v) settings.buyStamina = v == true end}) upSec:AddToggle({Name = "Buy treadmills", Default = true, Flag = "cfae_buy_treadmill", Description = "Better treadmills train speed faster.", Callback = function(v) settings.buyTreadmill = v == true end}) upSec:AddToggle({Name = "Buy base slots", Default = true, Flag = "cfae_buy_base", Callback = function(v) settings.buyBase = v == true end}) upSec:AddSlider({Name = "Keep in reserve", Min = 0, Max = 90, Default = 0, Increment = 5, Suffix = " %", Flag = "cfae_reserve", Description = "Only spends what's above this share of your cash.", Callback = function(v) settings.reserve = math.clamp(tonumber(v) or 0, 0, 90) end}) ui.nextBuy = upSec:AddLabel({Text = "-", Style = "Sub"}) local rbSec = upTab:CreateSection("Rebirth") rbSec:AddToggle({Name = "Rebirth when ready", Default = true, Flag = "cfae_rebirth", Description = "Rebirth only resets speed and raises your cash multiplier.", Callback = function(v) settings.rebirth = v == true end}) ui.rebirth = rbSec:AddLabel({Text = "-", Style = "Sub"}) local rewardTab = window:CreateTab({Name = "Rewards", Icon = "gift"}) local rewardSec = rewardTab:CreateSection("Free stuff") rewardSec:AddToggle({Name = "Claim free rewards", Default = true, Flag = "cfae_rewards", Description = "Playtime gifts, the daily reward, index rewards and offline cash.", Callback = function(v) settings.rewards = v == true end}) rewardSec:AddToggle({Name = "Anti AFK", Default = true, Flag = "cfae_afk", Description = "Roblox kicks you after 20 idle minutes otherwise.", Callback = function(v) settings.antiAfk = v == true end}) local logTab = window:CreateTab({Name = "Log", Icon = "list"}) local logSec = logTab:CreateSection("What the farm did") ui.log = {} for i = 1, 14 do ui.log[i] = logSec:AddLabel({Text = i == 1 and "nothing yet" or "", Style = "Sub"}) end logSec:AddButton({Name = "Copy the whole log", ButtonText = "Copy", Callback = function() if setclipboard then setclipboard(table.concat(logLines, "\n")) window:Notify({Title = "Log", Content = "Copied " .. #logLines .. " lines.", Type = "Success", Duration = 3}) end end}) local function minutes(s) s = math.floor(s) if s < 60 then return s .. "s" end if s < 3600 then return math.floor(s / 60) .. "m" end return math.floor(s / 3600) .. "h " .. math.floor((s % 3600) / 60) .. "m" end task.spawn(function() local shownLog = -1 while alive do pcall(function() local text = {} text.status = farm.enabled and farm.status or "off" text.session = string.format("this session: %d eggs, %d lost, %d hatched, %d bought, %d rebirths, %d candy, %d candy eggs, %s", stats.taken, stats.lost, stats.hatched, stats.bought, stats.rebirths, stats.candy, stats.candyEggs, minutes(os.clock() - stats.started)) text.account = string.format("cash $%s (%s/s), speed %s, stamina %s, treadmill %s, rebirths %s", short(data("Cash")), short(plr:GetAttribute("CashPerSecond")), short(data("Speed")), tostring(data("StaminaLevel")), tostring(data("TreadmillLevel")), tostring(data("Rebirths"))) local egg, why = nextEgg() text.next = egg and string.format("next: %s in %s, %s/s, about %ds there and back", eggLabel(egg.name, egg.variant), egg.biome, short(egg.value), math.floor(egg.trip)) or ("next: nothing (" .. tostring(why) .. ")") local isNight, toNight, toDay = nightState() text.night = isNight and ("night, eggs restock in " .. minutes(toDay)) or ("night in " .. minutes(toNight)) local list = animals() local onBase = 0 for _, a in ipairs(list) do if a.equipped then onBase = onBase + 1 end end text.base = string.format("%d / %s animals on the base, %d spare, %d eggs growing", onBase, tostring(data("MaxAnimals")), #list - onBase, count(data("PlacedEggs"))) local opts = upgradeOptions() text.nextBuy = opts[1] and ("next: " .. NAMES[opts[1].what] .. " for $" .. short(opts[1].cost)) or "next: nothing left to buy" local n = tonumber(data("Rebirths")) or 0 local okr, req = pcall(rebirthConfig.GetRequirements, n) local need = okr and type(req) == "table" and req.Speed text.rebirth = need and string.format("speed %s / %s", short(data("Speed")), short(need)) or "-" elevate() for key, value in pairs(text) do ui[key]:Set(value) end if lastLogAt ~= shownLog then shownLog = lastLogAt for i = 1, #ui.log do ui.log[i]:Set(logLines[i] or "") end end end) task.wait(0.5) end end) ]=]}; print("[catn hub] starting"); local hubOk, hubRes = xpcall(function() if not game:IsLoaded() then game.Loaded:Wait(); end local Players = game:GetService("Players"); local TeleportService = game:GetService("TeleportService"); local VirtualUser = game:GetService("VirtualUser"); local Lighting = game:GetService("Lighting"); local MarketplaceService = game:GetService("MarketplaceService"); local HttpService = game:GetService("HttpService"); local rs = game:GetService("ReplicatedStorage"); local plr = Players.LocalPlayer; local HUB_VERSION = "1.6.4"; local INVITE_CODE = "TwqtNreVMr"; local INVITE_URL = "https://discord.gg/" .. INVITE_CODE; local GAMES = {{Name="Anime Battle Arena",Key="aba",Icon="swords",Version="1.3.1",Detect=function() return (game.GameId == 578392296) or (game.PlaceId == 1458767429); end,Source=SOURCES.aba},{Name="Monday Morning Misery",Key="mmm",Icon="music",Version="1.1.1",Detect=function() local m = rs:FindFirstChild("Modules"); return (m ~= nil) and (m:FindFirstChild("Songs") ~= nil) and (m:FindFirstChild("CommonEffects") ~= nil); end,Source=SOURCES.mmm},{Name="Climb For Animals Eggs",Key="cfae",Icon="egg",Version="1.4.0",Detect=function() return (game.GameId == 10765490774) or (game.PlaceId == 85738654635245); end,Source=SOURCES.cfae}}; local genv = (getgenv and getgenv()) or _G; if (genv.__CATN_HUB and not genv.__CATN_HUB.Destroyed) then pcall(function() genv.__CATN_HUB:Destroy(); end); end local afkConn; local function antiAfk(on) if (on and not afkConn) then afkConn = plr.Idled:Connect(function() pcall(function() VirtualUser:CaptureController(); VirtualUser:ClickButton2(Vector2.new()); end); end); elseif (not on and afkConn) then afkConn:Disconnect(); afkConn = nil; end end local lowState; local function lowGraphics(on) if (on and not lowState) then local ok, level = pcall(function() return settings().Rendering.QualityLevel; end); lowState = {quality=((ok and level) or nil),shadows=Lighting.GlobalShadows}; pcall(function() settings().Rendering.QualityLevel = Enum.QualityLevel.Level01; end); Lighting.GlobalShadows = false; elseif (not on and lowState) then if lowState.quality then pcall(function() settings().Rendering.QualityLevel = lowState.quality; end); end Lighting.GlobalShadows = lowState.shadows; lowState = nil; end end local win = Vanta:Window({Title="Catn Hub",Subtitle=("v" .. HUB_VERSION),Icon="cat",Key=Enum.KeyCode.RightControl,Config="CatnHub",Theme=((Vanta.ThemeActive("Halloween") and "Halloween") or nil),OnDestroy=function() antiAfk(false); lowGraphics(false); end}); genv.__CATN_HUB = win; local gameName = "..."; local function copyText(text, what) if ((type(setclipboard) == "function") and pcall(setclipboard, text)) then win:Notify({Title="Copied",Content=(what .. " is on your clipboard."),Type="Success",Duration=3}); else win:Notify({Title=what,Content=("This executor can't copy to the clipboard: " .. text),Type="Info",Duration=10}); end end local function getText(url) local send = request or http_request or (syn and syn.request) or (http and http.request); if send then local ok, res = pcall(send, {Url=url,Method="GET"}); if (ok and (type(res) == "table") and (res.StatusCode == 200) and (type(res.Body) == "string")) then return res.Body; end end local ok, res = pcall(function() return game:HttpGet(url); end); if (ok and (type(res) == "string")) then return res; end end local function getJson(url) local body = getText(url); if not body then return nil; end local ok, data = pcall(HttpService.JSONDecode, HttpService, body); return (ok and data) or nil; end local function run(entry) local fn, err = loadstring(entry.Source, "=Catn Hub (" .. entry.Name .. ")"); if not fn then win:Notify({Title="Catn Hub",Content=(entry.Name .. " didn't compile: " .. tostring(err)),Type="Error",Duration=8}); return false; end local ok, res = pcall(fn, BPUI); if setthreadidentity then pcall(setthreadidentity, 8); end if not ok then warn("[Catn Hub] " .. entry.Name .. ": " .. tostring(res)); win:Notify({Title="Catn Hub",Content=(entry.Name .. " failed to start: " .. tostring(res)),Type="Error",Duration=8}); return false; end return true; end local loaded = false; local function load(entry) if loaded then win:Notify({Title=entry.Name,Content="Already loaded.",Type="Info"}); return; end loaded = true; if run(entry) then win:SetBadge(true); win:SetOpen(false); win:Notify({Title=entry.Name,Content="Loaded. Click the Catn icon or press Right Ctrl to open the hub again.",Type="Success"}); else loaded = false; end end local function unloadAll() local n = 0; for _, w in ipairs(BPUI.Windows) do if not w.Destroyed then pcall(function() w:Destroy(); end); n = n + 1; end end BPUI.Windows = {}; loaded = false; if not win.Destroyed then win:SetBadge(false); end return n; end BPUI.WindowGone = function() if win.Destroyed then return; end for _, w in ipairs(BPUI.Windows) do if not w.Destroyed then return; end end loaded = false; win:SetBadge(false); end; local function panic() unloadAll(); win:Destroy(); end local function openDiscord() local opened = false; local send = request or http_request or (syn and syn.request) or (http and http.request); if send then local ok, res = pcall(send, {Url="http://127.0.0.1:6463/rpc?v=1",Method="POST",Headers={["Content-Type"]="application/json",Origin="https://discord.com"},Body=HttpService:JSONEncode({cmd="INVITE_BROWSER",args={code=INVITE_CODE},nonce=HttpService:GenerateGUID(false)})}); opened = ok and (type(res) == "table") and (res.StatusCode == 200); end if opened then win:Notify({Title="Discord",Content="Opening the invite in Discord.",Type="Success"}); return; end local copied = (type(setclipboard) == "function") and pcall(setclipboard, INVITE_URL); if copied then win:Notify({Title="Discord",Content="Couldn't reach the Discord app, so the invite link was copied. Paste it in your browser.",Type="Info",Duration=7}); else win:Notify({Title="Discord",Content=INVITE_URL,Type="Info",Duration=12}); end end local function rejoin() local ok, err; if (#Players:GetPlayers() <= 1) then ok, err = pcall(TeleportService.Teleport, TeleportService, game.PlaceId, plr); else ok, err = pcall(TeleportService.TeleportToPlaceInstance, TeleportService, game.PlaceId, game.JobId, plr); end if not ok then win:Notify({Title="Rejoin",Content=("Couldn't teleport: " .. tostring(err)),Type="Error",Duration=8}); end end local function serverHop() win:Notify({Title="Server hop",Content="Looking for another server.",Type="Info",Duration=3}); task.spawn(function() local data = getJson("https://games.roblox.com/v1/games/" .. game.PlaceId .. "/servers/Public?sortOrder=Asc&limit=100&excludeFullGames=true"); local list = data and data.data; if (type(list) ~= "table") then win:Notify({Title="Server hop",Content="Couldn't get the server list. Try again in a moment.",Type="Error"}); return; end local choices = {}; for _, s in ipairs(list) do if ((s.id ~= game.JobId) and (type(s.playing) == "number") and (type(s.maxPlayers) == "number") and (s.playing < (s.maxPlayers - 1))) then table.insert(choices, s); end end if (#choices == 0) then win:Notify({Title="Server hop",Content="No other open server found.",Type="Warning"}); return; end local pick = choices[math.random(1, #choices)]; win:Notify({Title="Server hop",Content=("Joining a server with " .. tostring(pick.playing) .. " players."),Type="Success",Duration=4}); local ok, err = pcall(TeleportService.TeleportToPlaceInstance, TeleportService, game.PlaceId, pick.id, plr); if not ok then win:Notify({Title="Server hop",Content=("Couldn't teleport: " .. tostring(err)),Type="Error",Duration=8}); end end); end local function debugInfo() local exec = "unknown"; if (type(identifyexecutor) == "function") then local ok, name, ver = pcall(identifyexecutor); if (ok and name) then exec = tostring(name) .. ((ver and (" " .. tostring(ver))) or ""); end end local names = {}; for _, w in ipairs(BPUI.Windows) do if not w.Destroyed then table.insert(names, tostring(w.Title)); end end local missing = {}; for n in pairs(Vanta.MissingIcons) do table.insert(missing, n); end table.sort(missing); return table.concat({("Catn Hub " .. HUB_VERSION),("Game: " .. gameName .. " (place " .. tostring(game.PlaceId) .. ", game " .. tostring(game.GameId) .. ")"),("Server: " .. tostring(game.JobId)),("Executor: " .. exec),("Loaded: " .. (((#names > 0) and table.concat(names, ", ")) or "nothing")),("Theme: " .. win.ThemeName),("Missing icons: " .. (((#missing > 0) and table.concat(missing, ", ")) or "none")),("Time: " .. os.date("!%Y-%m-%d %H:%M UTC"))}, "\n"); end local home = win:Tab({Name="Game",Icon="gamepad-2",Desc="What you're playing and which script fits"}); local here = home:Section("This game"); local nameRow = here:Stat({Name="Game",Icon="gamepad-2",Value="..."}); here:Stat({Name="Place ID",Icon="hash",Value=tostring(game.PlaceId)}); local statusRow = here:Stat({Name="Status",Icon="shield-check",Value="Checking"}); local result = home:Section("Result"):Paragraph({Title="Checking this game",Content="One moment."}); local community = home:Section("Community"); community.Frame.LayoutOrder = 9000; community:Button({Name="Discord",Icon="message-circle",Desc="Join the Catn Hub server",ButtonText="Join",Callback=openDiscord}); local utils = win:Tab({Name="Utilities",Icon="wrench",Desc="Tools that work in every game"}); local session = utils:Section("Session"); session:Toggle({Name="Anti AFK",Icon="timer",Desc="Stops the game kicking you for being idle",Flag="anti_afk",Callback=antiAfk}); session:Button({Name="Rejoin",Icon="refresh-cw",Desc="Leaves and comes straight back to this server",ButtonText="Rejoin",Callback=function() win:Dialog({Title="Rejoin this server?",Content="You'll leave the game and come straight back. Anything unsaved is lost.",Buttons={{Text="Cancel"},{Text="Rejoin",Style="Primary",Callback=rejoin}}}); end}); session:Button({Name="Server hop",Icon="shuffle",Desc="Moves you to a different public server",ButtonText="Hop",Callback=function() win:Dialog({Title="Hop to another server?",Content="You'll leave this server and join a different one.",Buttons={{Text="Cancel"},{Text="Hop",Style="Primary",Callback=serverHop}}}); end}); local perf = utils:Section("Performance"); perf:Toggle({Name="Low graphics",Icon="monitor",Desc="Lowers the quality level and turns shadows off",Flag="low_gfx",Callback=lowGraphics}); local control = utils:Section("Scripts"); control:Button({Name="Unload all",Icon="power",Desc="Turns off every script the hub loaded",ButtonText="Unload",Style="Danger",Callback=function() local n = unloadAll(); win:SetOpen(true); win:Notify({Title="Unloaded",Content=(((n == 0) and "Nothing was loaded.") or ("Turned off " .. n .. (((n == 1) and " script.") or " scripts."))),Type="Info"}); end}); control:Keybind({Name="Panic key",Icon="siren",Desc="Unloads every script and closes the hub, no questions asked",Default=Enum.KeyCode.End,Callback=panic}); local about = utils:Section("About"); about:Stat({Name="Version",Icon="tag",Value=HUB_VERSION}); about:Button({Name="Place ID",Icon="hash",ButtonText="Copy",Callback=function() copyText(tostring(game.PlaceId), "Place ID"); end}); about:Button({Name="Server ID",Icon="server",ButtonText="Copy",Callback=function() copyText(tostring(game.JobId), "Server ID"); end}); about:Button({Name="Debug info",Icon="bug",Desc="Copies details to paste when you report a problem",ButtonText="Copy",Callback=function() copyText(debugInfo(), "Debug info"); end}); win.CatnApi = {load=load,unloadAll=unloadAll,panic=panic,rejoin=rejoin,serverHop=serverHop,debugInfo=debugInfo,antiAfk=antiAfk}; task.spawn(function() local ok, info = pcall(MarketplaceService.GetProductInfo, MarketplaceService, game.PlaceId); if win.Destroyed then return; end gameName = (ok and info and info.Name) or "Unknown"; nameRow:Set(gameName); end); local function detect() local found, verdicts = nil, {}; for i, entry in ipairs(GAMES) do local ok, yes = pcall(entry.Detect); verdicts[i] = ok and (yes == true); if (verdicts[i] and not found) then found = entry; end end return found, verdicts; end task.spawn(function() local found, verdicts = detect(); if (not found and not rs:FindFirstChild("Modules")) then rs:WaitForChild("Modules", 4); found, verdicts = detect(); end if win.Destroyed then return; end if found then statusRow:Set("Supported"); result:SetTitle(found.Name .. " is supported"); result:Set("The script for this game is ready. Press Load to open its menu."); local sec = home:Section("Script"); sec:Button({Name=found.Name,Icon=found.Icon,Desc="Opens the full menu for this game",ButtonText="Load",Style="Primary",Callback=function() load(found); end}); local auto = sec:Toggle({Name="Load automatically",Icon="zap",Desc="Loads it as soon as you join this game",Flag=("autoload_" .. found.Key)}); if auto:Get() then win:Notify({Title=found.Name,Content="Loading automatically. You can turn that off in the Game tab.",Type="Info",Duration=4}); task.delay(1.5, function() if not win.Destroyed then load(found); end end); else win:Notify({Title="Supported",Content=(found.Name .. " is ready to load."),Type="Success"}); end else statusRow:Set("Not supported"); result:SetTitle("This game isn't supported"); result:Set("We only have scripts for Anime Battle Arena and Monday Morning Misery. Join one of them and run the hub again. The Utilities tab still works here."); win:Notify({Title="Not supported",Content="No script for this game yet.",Type="Warning"}); end local list = home:Section("Our scripts"); for i, entry in ipairs(GAMES) do list:Stat({Name=entry.Name,Icon=entry.Icon,Value=("v" .. entry.Version .. " · " .. ((verdicts[i] and "This game") or "Not this game"))}); end end); local preview = win:Group({Name="Preview",Open=false}); local controls = preview:Tab({Name="Controls",Icon="sliders-horizontal",Desc="Toggles, sliders and pickers"}); local main = controls:Section("Example"); local sample = main:Toggle({Name="Toggle",Desc="Switches with a short slide",Flag="sample_toggle"}); main:Keybind({Name="Keybind",Default=Enum.KeyCode.F1,Flag="sample_key",Callback=function() sample:Set(not sample:Get()); end}); main:Slider({Name="Slider",Min=0,Max=100,Step=5,Default=40,Suffix="%",Flag="sample_slider"}); main:Dropdown({Name="Dropdown",Options={"First","Second","Third"},Default="First",Flag="sample_drop"}); main:Dropdown({Name="Multi select",Multi=true,Options={"Red","Green","Blue"},Default={"Green"},Flag="sample_multi"}); main:Input({Name="Text box",Placeholder="Type here",Flag="sample_input"}); main:ColorPicker({Name="Color",Default=Color3.fromRGB(120, 160, 255),Flag="sample_color"}); local parts = preview:Tab({Name="Components",Icon="bell",Desc="Notifications and dialogs"}); local fx = parts:Section("Actions"); fx:Button({Name="Notifications",Desc="One of each kind",ButtonText="Send",Callback=function() win:Notify({Title="Settings saved",Content="Your changes will apply next run.",Type="Info"}); task.wait(0.12); win:Notify({Title="Run finished",Content="42 caught in 6m 12s.",Type="Success"}); task.wait(0.12); win:Notify({Title="Low health",Content="Pausing until you recover.",Type="Warning"}); task.wait(0.12); win:Notify({Title="Request failed",Content="Couldn't reach the server.",Type="Error"}); end}); fx:Button({Name="Dialog",ButtonText="Open",Callback=function() win:Dialog({Title="Reset all settings?",Content="Every option goes back to its default. This can't be undone.",Buttons={{Text="Cancel"},{Text="Reset",Style="Danger"}}}); end}); end, function(e) return tostring(e) .. "\n" .. debug.traceback(); end); if not hubOk then warn("[catn hub] failed to start: " .. tostring(hubRes)); end return hubRes;