-- Kingfisher / Tribes 3v3 -- standalone client/executor script -- Original implementation. No downloads, forged remote calls, or external UI libraries. -- GUI controls: ESP, aim, arc, names, target part, FOV, minimize and unload. -- Enable AIM in the panel; aim follows only during a bow draw. Insert toggles the menu. -- Optional native bow automation and scoped silent direction; both start OFF. -- Jump prediction models gravity and an estimated landing. Native events give charge. -- Run in the live game client; a saveinstance lacks the server needed for a full match. local Config = { ESP = true, Aim = false, SilentAim = false, AutoBow = false, SmartCharge = true, JumpPrediction = true, NoRecoil = false, StrafePrediction = true, -- smooth velocity + collapse lead on direction changes StrafeTau = 0.09, -- velocity smoothing / lead-recovery time constant (s) NoSpread = false, -- server-consistent no-spread via shot-id seed search (guns) CircleStrafe = true, -- hold [C]: orbit / park behind target (auto-fly) CircleStrafeMode = "Orbit", -- "Orbit" or "BehindBack"; tap [B] to switch ShowHud = true, -- on-screen keybind + active-feature panel Fly = false, -- menu toggle: free-fly (WASD + space/shift) Speed = false, -- menu toggle: walk-speed boost SuperJump = false, -- menu toggle: high jump AutoMinCharge = 0.35, AutoMaxFlight = 0.75, AutoInterval = 0.05, AutoLostTargetGrace = 0.4, AutoMaxHold = 3, Trajectory = true, Names = true, FOVRadius = 180, MaxDistance = 650, IncludeTrainingDummies = true, PreferHighArc = false, TargetPart = "UpperTorso", TargetRefresh = 0.25, SelectInterval = 0.05, TrajectoryInterval = 1 / 144, IdleTrajectoryInterval = 1 / 144, CastStep = 1 / 45, MaxLifetime = 5, MaxTravel = 1200, MaxCandidates = 3, ExtraLeadSeconds = 0, RunMathTests = false, } local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UIS = game:GetService("UserInputService") local GuiService = game:GetService("GuiService") local CollectionService = game:GetService("CollectionService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Workspace = game:GetService("Workspace") local HttpService = game:GetService("HttpService") local player = Players.LocalPlayer assert(player and RunService:IsClient(), "[Kingfisher] Run this in the game client.") -- Settings persistence ------------------------------------------------------- -- Auto-saves the menu's toggles to the executor's data folder and reloads them -- on the next run, so the script returns exactly how you left it. Silently a -- no-op on executors without a filesystem (readfile/writefile/isfile). local CONFIG_FILE = "kingfisher_tribes_config.json" local PERSIST = { "ESP", "Aim", "SilentAim", "AutoBow", "SmartCharge", "JumpPrediction", "NoRecoil", "StrafePrediction", "Trajectory", "Names", "FOVRadius", "PreferHighArc", "TargetPart", "CircleStrafe", "CircleStrafeMode", "ShowHud", "NoSpread", "Fly", "Speed", "SuperJump", } local fsRead = type(readfile) == "function" and readfile or nil local fsWrite = type(writefile) == "function" and writefile or nil local fsIsFile = type(isfile) == "function" and isfile or nil local function serializeConfig() local out = {} for _, key in ipairs(PERSIST) do out[key] = Config[key] end local ok, encoded = pcall(function() return HttpService:JSONEncode(out) end) return ok and encoded or nil end local function loadConfig() if not (fsRead and fsIsFile) then return end local ok, raw = pcall(function() if fsIsFile(CONFIG_FILE) then return fsRead(CONFIG_FILE) end return nil end) if not ok or type(raw) ~= "string" then return end local decoded ok, decoded = pcall(function() return HttpService:JSONDecode(raw) end) if not ok or type(decoded) ~= "table" then return end for _, key in ipairs(PERSIST) do local saved = decoded[key] if saved ~= nil and type(saved) == type(Config[key]) then Config[key] = saved end end end local lastSavedSnapshot local function saveConfig() if not fsWrite then return end local encoded = serializeConfig() if encoded and encoded ~= lastSavedSnapshot then if pcall(fsWrite, CONFIG_FILE, encoded) then lastSavedSnapshot = encoded end end end loadConfig() lastSavedSnapshot = serializeConfig() local playerGui = player:WaitForChild("PlayerGui", 15) assert(playerGui, "[Kingfisher] PlayerGui did not load.") local ROOT_NAME = "__KingfisherTribes_v1" local old = playerGui:FindFirstChild(ROOT_NAME) if old then local stop = old:FindFirstChild("Shutdown") if stop and stop:IsA("BindableEvent") then stop:Fire(); task.wait() end if old.Parent then old:Destroy() end end local connections, destructors = {}, {} local active = true local renderFailed = false local binding = ROOT_NAME .. "_" .. tostring(math.floor(os.clock() * 1000000)) local menuBinding = binding .. "_Menu" local stopAuto, installBowAdapters, installRecoilControl local bowAdaptersReady = false local autoNote = "Auto: OFF" local windowFocused = true local function connect(signal, fn) local connection = signal:Connect(fn) table.insert(connections, connection) return connection end local gui = Instance.new("ScreenGui") gui.Name = ROOT_NAME gui.ResetOnSpawn = false gui.IgnoreGuiInset = true gui.Enabled = true gui.DisplayOrder = 1000 gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling gui.Parent = playerGui local shutdown = Instance.new("BindableEvent") shutdown.Name = "Shutdown" shutdown.Parent = gui local visuals = Instance.new("Folder") visuals.Name = ROOT_NAME visuals.Parent = Workspace local function unload() if not active then return end active = false RunService:UnbindFromRenderStep(binding) RunService:UnbindFromRenderStep(menuBinding) for _, connection in ipairs(connections) do connection:Disconnect() end for _, destructor in ipairs(destructors) do pcall(destructor) end visuals:Destroy() gui:Destroy() print("[Kingfisher] Unloaded.") end connect(shutdown.Event, unload) connect(gui.Destroying, unload) local function make(class, properties, parent) local object = Instance.new(class) for key, value in pairs(properties) do object[key] = value end object.Parent = parent return object end local function rounded(object, radius) make("UICorner", {CornerRadius = UDim.new(0, radius)}, object) end local PANEL_WIDTH, PANEL_HEIGHT = 342, 486 local panel = make("Frame", { Name = "Menu", Visible = true, Position = UDim2.fromOffset(20, 90), Size = UDim2.fromOffset(PANEL_WIDTH, PANEL_HEIGHT), BackgroundColor3 = Color3.fromRGB(15, 23, 30), BackgroundTransparency = 0.04, BorderSizePixel = 0, }, gui) rounded(panel, 9) make("UIStroke", {Color = Color3.fromRGB(47, 83, 90), Thickness = 1}, panel) local function textLabel(parent, text, y, height) return make("TextLabel", { Position = UDim2.fromOffset(12, y), Size = UDim2.new(1, -24, 0, height), BackgroundTransparency = 1, Text = text, TextSize = 13, Font = Enum.Font.Code, TextColor3 = Color3.fromRGB(221, 231, 237), TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, TextYAlignment = Enum.TextYAlignment.Center, }, parent) end local title = textLabel(panel, "KINGFISHER / TRIBES", 8, 24) title.Size = UDim2.new(1, -96, 0, 24) title.TextColor3 = Color3.fromRGB(87, 221, 211) local content = make("Frame", { Position = UDim2.fromOffset(0, 42), Size = UDim2.new(1, 0, 1, -42), BackgroundTransparency = 1, }, panel) local function button(parent, caption, x, y, width, height) local result = make("TextButton", { Position = UDim2.fromOffset(x, y), Size = UDim2.fromOffset(width, height), BackgroundColor3 = Color3.fromRGB(32, 47, 58), BorderSizePixel = 0, TextSize = 13, Font = Enum.Font.Code, TextColor3 = Color3.new(1, 1, 1), Text = caption, }, parent) rounded(result, 5) return result end local minimize = button(panel, "-", PANEL_WIDTH - 76, 8, 28, 26) local mouseIconBeforeMenu = UIS.MouseIconEnabled minimize.Modal = true -- Free the cursor only while the menu is visible. table.insert(destructors, function() minimize.Modal = false if panel.Visible then UIS.MouseIconEnabled = mouseIconBeforeMenu end end) local close = button(panel, "X", PANEL_WIDTH - 40, 8, 28, 26) close.BackgroundColor3 = Color3.fromRGB(91, 44, 49) connect(close.Activated, unload) connect(minimize.Activated, function() content.Visible = not content.Visible panel.Size = UDim2.fromOffset(PANEL_WIDTH, content.Visible and PANEL_HEIGHT or 42) minimize.Text = content.Visible and "-" or "+" end) local buttons = {} for i, entry in ipairs({{"ESP", "ESP"}, {"Aim", "AIM"}, {"Trajectory", "ARC"}}) do local key, caption = entry[1], entry[2] local control = button(content, caption, 12 + (i - 1) * 108, 0, 102, 32) buttons[key] = {button = control, caption = caption} connect(control.Activated, function() Config[key] = not Config[key] if key == "Aim" and not Config.Aim then Config.AutoBow = false if stopAuto then stopAuto("Aim disabled") end end end) end local namesButton = button(content, "NAMES ON", 12, 42, 102, 30) local partButton = button(content, "TARGET: TORSO", 120, 42, 210, 30) connect(namesButton.Activated, function() Config.Names = not Config.Names end) connect(partButton.Activated, function() Config.TargetPart = Config.TargetPart == "Head" and "UpperTorso" or "Head" end) local fovLabel = textLabel(content, "AIM FOV: 180 px", 85, 26) fovLabel.Size = UDim2.fromOffset(225, 26) local less = button(content, "-", 254, 84, 32, 28) local more = button(content, "+", 298, 84, 32, 28) connect(less.Activated, function() Config.FOVRadius = math.max(40, Config.FOVRadius - 20) end) connect(more.Activated, function() Config.FOVRadius = math.min(400, Config.FOVRadius + 20) end) local arcButton = button(content, "ARC: LOW / FAST", 12, 124, 318, 30) connect(arcButton.Activated, function() Config.PreferHighArc = not Config.PreferHighArc end) local modeButton = button(content, "AIM: CAMERA", 12, 164, 156, 30) local autoButton = button(content, "AUTO FIRE OFF", 174, 164, 156, 30) local smartButton = button(content, "SMART CHARGE ON", 12, 202, 156, 30) local jumpButton = button(content, "JUMP LEAD ON", 174, 202, 156, 30) connect(modeButton.Activated, function() if not bowAdaptersReady then autoNote = "Silent: native adapter unavailable"; return end Config.SilentAim = not Config.SilentAim end) connect(autoButton.Activated, function() if not bowAdaptersReady then autoNote = "Auto: native adapter unavailable"; return end Config.AutoBow = not Config.AutoBow if Config.AutoBow then Config.Aim = true elseif stopAuto then stopAuto("OFF") end end) connect(smartButton.Activated, function() Config.SmartCharge = not Config.SmartCharge end) connect(jumpButton.Activated, function() Config.JumpPrediction = not Config.JumpPrediction end) local recoilButton = button(content, "NO RECOIL OFF", 12, 240, 156, 30) connect(recoilButton.Activated, function() Config.NoRecoil = not Config.NoRecoil end) local spreadButton = button(content, "NO SPREAD OFF", 174, 240, 156, 30) connect(spreadButton.Activated, function() Config.NoSpread = not Config.NoSpread end) local flyButton = button(content, "FLY OFF", 12, 278, 102, 30) connect(flyButton.Activated, function() Config.Fly = not Config.Fly end) local speedButton = button(content, "SPEED OFF", 120, 278, 102, 30) connect(speedButton.Activated, function() Config.Speed = not Config.Speed end) local jumpBoostButton = button(content, "JUMP OFF", 228, 278, 102, 30) connect(jumpBoostButton.Activated, function() Config.SuperJump = not Config.SuperJump end) local status = textLabel(content, "Loading game adapters...", 317, 20) local targetLabel = textLabel(content, "Enable AIM, then fire your weapon", 339, 20) local adapterLabel = textLabel(content, "Charge: waiting | Origin: fallback", 361, 18) adapterLabel.TextSize = 11 local autoLabel = textLabel(content, "Auto: OFF", 383, 18) autoLabel.TextSize = 11 textLabel(content, "Auto runs with this menu hidden.", 408, 17).TextSize = 11 textLabel(content, "Insert: hide/show menu. [X]: unload.", 426, 16).TextSize = 11 local dragging, dragStart, panelStart, dragInput local dragHandle = make("TextButton", { Position = UDim2.fromOffset(0, 0), Size = UDim2.new(1, -84, 0, 40), BackgroundTransparency = 1, Text = "", AutoButtonColor = false, }, panel) connect(dragHandle.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging, dragStart, panelStart, dragInput = true, input.Position, panel.Position, input end end) connect(UIS.InputChanged, function(input) if not dragging then return end if input.UserInputType ~= Enum.UserInputType.MouseMovement and input ~= dragInput then return end local delta = input.Position - dragStart local camera = Workspace.CurrentCamera if not camera then return end panel.Position = UDim2.fromOffset( math.clamp(panelStart.X.Offset + delta.X, 0, math.max(0, camera.ViewportSize.X - PANEL_WIDTH)), math.clamp(panelStart.Y.Offset + delta.Y, 0, math.max(0, camera.ViewportSize.Y - panel.AbsoluteSize.Y)) ) end) connect(UIS.InputEnded, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input == dragInput then dragging = false end end) local ring = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromOffset(Config.FOVRadius * 2, Config.FOVRadius * 2), BackgroundTransparency = 1, BorderSizePixel = 0, }, gui) make("UICorner", {CornerRadius = UDim.new(1, 0)}, ring) make("UIStroke", {Color = Color3.fromRGB(79, 200, 211), Transparency = 0.55, Thickness = 1}, ring) local aimDot = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Size = UDim2.fromOffset(7, 7), BackgroundColor3 = Color3.fromRGB(255, 219, 103), BorderSizePixel = 0, Visible = false, }, gui) rounded(aimDot, 4) local modules = {} local menuCamera local function releaseMenuMouse() if not menuCamera then return end local previous = menuCamera menuCamera = nil local ok, err = pcall(previous.PopMouseUnlock, binding) if not ok then warn("[Kingfisher] Mouse unlock cleanup failed: " .. tostring(err)) end end local function syncMenuMouse() local desired = active and gui.Enabled and panel.Visible and modules.Camera or nil if desired and (type(desired.PushMouseUnlock) ~= "function" or type(desired.PopMouseUnlock) ~= "function") then desired = nil end if desired == menuCamera then return end releaseMenuMouse() if desired then local ok, err = pcall(desired.PushMouseUnlock, binding) if ok then menuCamera = desired else warn("[Kingfisher] Native menu mouse control unavailable: " .. tostring(err)) end end end table.insert(destructors, releaseMenuMouse) local nativeDraw = false local drawing = false local drawStart, drawDuration = 0, 1 local lastTool local heldFallback = false local panelHovered = false local selected, selectionTime = nil, -math.huge local applyAim -- The native Release callback runs immediately before the bow computes its shot. local autoHandler, autoOwned, autoReleaseResult local instantAutoFiring = false -- true only during an auto tap on an instant weapon local firingContexts = setmetatable({}, {__mode = "k"}) local autoNext, autoLastClear, autoStarted = 0, 0, 0 connect(panel.MouseEnter, function() panelHovered = true end) connect(panel.MouseLeave, function() panelHovered = false end) local function setMenuVisible(visible) if not active then return end local wasVisible = gui.Enabled and panel.Visible if visible and not wasVisible then mouseIconBeforeMenu = UIS.MouseIconEnabled end if visible then if stopAuto then stopAuto("Paused: menu open") end gui.Enabled = true content.Visible = true panel.Size = UDim2.fromOffset(PANEL_WIDTH, PANEL_HEIGHT) minimize.Text = "-" local camera = Workspace.CurrentCamera if camera then panel.Position = UDim2.fromOffset( math.clamp(panel.Position.X.Offset, 0, math.max(0, camera.ViewportSize.X - PANEL_WIDTH)), math.clamp(panel.Position.Y.Offset, 0, math.max(0, camera.ViewportSize.Y - PANEL_HEIGHT)) ) end end panel.Visible = visible minimize.Modal = visible dragging, dragInput, panelHovered = false, nil, false if visible then UIS.MouseIconEnabled = true else UIS.MouseIconEnabled = mouseIconBeforeMenu -- Removing Modal lets the game's camera/shift-lock control the mouse again. end syncMenuMouse() end connect(gui:GetPropertyChangedSignal("Enabled"), syncMenuMouse) -- Register menu controls before loading adapters or building gameplay visuals. connect(UIS.InputBegan, function(input) if input.KeyCode ~= Enum.KeyCode.Insert then return end if UIS:GetFocusedTextBox() or GuiService.MenuIsOpen then return end setMenuVisible(not (gui.Enabled and panel.Visible)) end) RunService:BindToRenderStep(menuBinding, Enum.RenderPriority.Camera.Value + 4, function() if active and gui.Enabled and panel.Visible then UIS.MouseIconEnabled = true end end) setMenuVisible(true) print("[Kingfisher] Menu ready. Insert hides/shows it.") local function loadModule(path, key) task.spawn(function() local cursor = path[1] for i = 2, #path do cursor = cursor and cursor:WaitForChild(path[i], 12) if not active or not cursor then return end end if not cursor:IsA("ModuleScript") then return end local ok, value = pcall(require, cursor) if not active then return end if not ok or type(value) ~= "table" then warn("[Kingfisher] " .. key .. " unavailable; using fallback.") return end modules[key] = value if key == "Camera" then syncMenuMouse() end if key == "Controller" and type(value.OnViewEvent) == "function" then local subscribed, disconnect = pcall(value.OnViewEvent, function(name, data) if not active or type(data) ~= "table" then return end if name == "Draw" then lastTool = player.Character and player.Character:FindFirstChildOfClass("Tool") drawing = data.on == true selected, selectionTime = nil, -math.huge if drawing then drawStart = os.clock() drawDuration = tonumber(data.time) or 1 end elseif name == "Release" then local ok, err = true, nil if applyAim and type(data.charge) == "number" then ok, err = pcall(applyAim, math.clamp(data.charge, 0, 1), true) end drawing, selected = false, nil if not ok then warn("[Kingfisher] Release adjustment failed: " .. tostring(err)) end end end) if subscribed and type(disconnect) == "function" then nativeDraw = true table.insert(destructors, disconnect) end end if installBowAdapters then installBowAdapters() end if installRecoilControl then installRecoilControl() end end) end loadModule({ReplicatedStorage, "Shared", "Weapons"}, "Weapons") loadModule({ReplicatedStorage, "Shared", "Camera"}, "Camera") loadModule({player, "PlayerScripts", "Combat", "Util"}, "Util") loadModule({player, "PlayerScripts", "Combat", "Controller"}, "Controller") loadModule({player, "PlayerScripts", "Combat", "Handlers", "Bow"}, "Bow") loadModule({player, "PlayerScripts", "Combat", "Handlers", "Gun"}, "Gun") loadModule({ReplicatedStorage, "Shared", "Combat"}, "Combat") -- Fallback ballistics for every projectile weapon, used when the game's own -- Shared.Weapons module cannot be required. Numbers mirror that module's tuning -- tables; the live definition overrides these whenever it is reachable. local fallbackWeapons = { short_bow = {kind = "Bow", drawTime = 0.5, speedMin = 120, speedMax = 250, gravity = 55, radius = 0.3, range = 400}, longbow = {kind = "Bow", drawTime = 1.1, speedMin = 160, speedMax = 380, gravity = 32, radius = 0.28, range = 600}, crossbow = {kind = "Crossbow", speed = 320, gravity = 28, radius = 0.28, range = 500}, musket = {kind = "Musket", speed = 900, gravity = 12, radius = 0.22, range = 600}, flintlock = {kind = "Pistol", speed = 700, gravity = 20, radius = 0.25, range = 400}, blunderbuss = {kind = "Blunderbuss", speed = 420, gravity = 20, radius = 0.3, range = 90}, throwing_knives = {kind = "Knives", speed = 240, gravity = 30, radius = 0.3, range = 300}, javelins = {kind = "Javelin", drawTime = 0.45, speedMin = 95, speedMax = 175, gravity = 62, radius = 0.45, range = 400}, harpoon = {kind = "Javelin", drawTime = 0.6, speedMin = 110, speedMax = 160, gravity = 55, radius = 0.5, range = 220}, sling = {kind = "Sling", speed = 150, gravity = 85, radius = 0.35, range = 350}, bolas = {kind = "Knives", speed = 150, gravity = 45, radius = 0.7, range = 160}, chakram = {kind = "Knives", speed = 110, gravity = 0, radius = 0.9, range = 45}, } -- Kinds whose shots are a single projectile we can lead a target with. -- Bomb is a lobbed AoE and the game skips aim-assist for it, so it is excluded. local AIMABLE_KINDS = { Bow = true, Crossbow = true, Musket = true, Pistol = true, Blunderbuss = true, Knives = true, Javelin = true, Sling = true, } -- Charge/draw weapons scale launch speed with charge (DrawnShot); the rest fire -- at a fixed speed on a single input. local CHARGE_KINDS = {Bow = true, Javelin = true} -- Firearms are hitscan server-side (the client projectile is only a tracer): -- the server raycasts instantly, so these need NO lead and NO drop -- aim dead -- at the target's current position. Bows/crossbow/throwables stay projectile. local HITSCAN_KINDS = {Musket = true, Pistol = true, Blunderbuss = true} local aimHitscan = false -- set by bowInfo() to the equipped weapon's hitscan flag local function weaponModel(kind) return CHARGE_KINDS[kind] and "charge" or "instant" end -- Returns tool, tuning, id, kind, model for any aimable projectile weapon, or nil. local function bowInfo() local character = player.Character local tool = character and character:FindFirstChildOfClass("Tool") if tool ~= lastTool then drawing, heldFallback = false, false selected, selectionTime = nil, -math.huge lastTool = tool end if not tool then return nil end local id = tool:GetAttribute("WeaponId") local fallback = fallbackWeapons[id] local tuning = fallback local kind = fallback and fallback.kind local weapons = modules.Weapons if weapons and type(weapons.Get) == "function" then local ok, definition = pcall(weapons.Get, id) if ok and type(definition) == "table" and AIMABLE_KINDS[definition.kind] then tuning = definition.tuning or tuning kind = definition.kind end end if not tuning or not kind or not AIMABLE_KINDS[kind] then return nil end aimHitscan = HITSCAN_KINDS[kind] == true return tool, tuning, id, kind, weaponModel(kind) end local function chargeFor(tuning) if drawing or (not nativeDraw and heldFallback) then local duration = nativeDraw and drawDuration or (tuning.drawTime or 1) return math.clamp((os.clock() - drawStart) / math.max(0.001, duration), 0, 1), true end return 1, false -- Idle visualization is explicitly a full-draw preview. end -- Neutralizes the client-side recoil/shake the game applies after a shot while -- Config.NoRecoil is on. These are purely local camera/view effects, so wrapping -- them is safe and fully reversible on unload. Reinstalled idempotently as the -- native Util module becomes available. local recoilCleanup installRecoilControl = function() if recoilCleanup or not active then return end local util = modules.Util if type(util) ~= "table" then return end local originals, wrappers = {}, {} for _, name in ipairs({"Recoil", "RecoilSlow", "Shake"}) do if type(util[name]) == "function" then originals[name] = util[name] end end if not next(originals) then return end for name, fn in pairs(originals) do local wrapped = function(...) if active and Config.NoRecoil then return end return fn(...) end wrappers[name] = wrapped util[name] = wrapped end recoilCleanup = function() for name, fn in pairs(originals) do if util[name] == wrappers[name] then util[name] = fn end end end table.insert(destructors, function() if recoilCleanup then recoilCleanup() end end) end installRecoilControl() local function attribute(model, owner, key) local value = model and model:GetAttribute(key) if value == nil and owner then value = owner:GetAttribute(key) end return value end local function isEnemy(model, owner) if model == player.Character or owner == player or not model:IsDescendantOf(Workspace) then return false end if attribute(model, owner, "Alive") == false then return false end local humanoid = model:FindFirstChildOfClass("Humanoid") if not humanoid or humanoid.Health <= 0 then return false end local myMatch = attribute(player.Character, player, "MatchId") local theirMatch = attribute(model, owner, "MatchId") local myTeam = attribute(player.Character, player, "Team") local theirTeam = attribute(model, owner, "Team") if type(myMatch) == "string" and myMatch ~= "" then return theirMatch == myMatch and theirTeam ~= nil and myTeam ~= nil and theirTeam ~= myTeam end return Config.IncludeTrainingDummies and CollectionService:HasTag(model, "TrainingDummy") end local records = {} local function refreshTargets() local visited, valid = {}, {} local function visit(model, owner) if not model or not model:IsA("Model") or visited[model] then return end visited[model] = true if not isEnemy(model, owner) then return end local root = model:FindFirstChild("HumanoidRootPart") local part = model:FindFirstChild(Config.TargetPart) or model:FindFirstChild("Torso") or model:FindFirstChild("Head") or root if not root or not root:IsA("BasePart") or not part or not part:IsA("BasePart") then return end valid[model] = true local head = model:FindFirstChild("Head") local adornee = head and head:IsA("BasePart") and head or root local record = records[model] if not record then local highlight = make("Highlight", { Adornee = model, DepthMode = Enum.HighlightDepthMode.AlwaysOnTop, FillColor = Color3.fromRGB(243, 87, 89), FillTransparency = 0.8, OutlineColor = Color3.fromRGB(255, 146, 127), OutlineTransparency = 0.1, }, visuals) local billboard = make("BillboardGui", { Adornee = adornee, AlwaysOnTop = true, Size = UDim2.fromOffset(220, 42), StudsOffsetWorldSpace = Vector3.new(0, 2.4, 0), MaxDistance = Config.MaxDistance, }, gui) local label = make("TextLabel", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, TextSize = 12, Font = Enum.Font.Code, TextColor3 = Color3.new(1, 1, 1), TextStrokeTransparency = 0.25, Text = "", }, billboard) record = {highlight = highlight, billboard = billboard, label = label, model = model} records[model] = record end record.owner, record.root, record.part = owner, root, part record.humanoid = model:FindFirstChildOfClass("Humanoid") record.billboard.Adornee = adornee end for _, other in ipairs(Players:GetPlayers()) do visit(other.Character, other) end for _, tag in ipairs({"Combatant", "Bot", "TrainingDummy"}) do for _, model in ipairs(CollectionService:GetTagged(tag)) do if model:IsA("Model") then visit(model, Players:GetPlayerFromCharacter(model)) end end end for model, record in pairs(records) do if not valid[model] then if selected and selected.record == record then selected, selectionTime = nil, -math.huge end record.highlight:Destroy() record.billboard:Destroy() records[model] = nil end end end local function exclusionContext() local list, seen = {}, {} local function add(object) if object and not seen[object] then seen[object] = true table.insert(list, object) end end add(visuals) add(player.Character) for _, name in ipairs({"FX", "Projectiles"}) do local folder = Workspace:FindFirstChild(name) add(folder) end local myMatch = attribute(player.Character, player, "MatchId") local myTeam = attribute(player.Character, player, "Team") local function teammate(model, owner) if model and model:IsA("Model") and myMatch ~= nil and myMatch ~= "" and myTeam ~= nil and attribute(model, owner, "MatchId") == myMatch and attribute(model, owner, "Team") == myTeam then add(model) end end for _, other in ipairs(Players:GetPlayers()) do teammate(other.Character, other) end for _, tag in ipairs({"Combatant", "Bot"}) do for _, model in ipairs(CollectionService:GetTagged(tag)) do teammate(model, nil) end end return {list = list, seen = seen, params = {}} end local function exclusions(extra, context) context = context or exclusionContext() local key = extra or false if context.params[key] then return context.params[key] end local list = table.clone(context.list) if extra and not context.seen[extra] then table.insert(list, extra) end local params = RaycastParams.new() params.FilterType = Enum.RaycastFilterType.Exclude params.FilterDescendantsInstances = list params.IgnoreWater = true context.params[key] = params return params end local function shotOrigin(tool, params) local util = modules.Util if util and type(util.ShotOrigin) == "function" then local ok, origin = pcall(util.ShotOrigin, tool, "Muzzle") if ok and typeof(origin) == "Vector3" then return origin end end local character = player.Character local head = character and (character:FindFirstChild("Head") or character:FindFirstChild("HumanoidRootPart")) if not head or not head:IsA("BasePart") then return nil end local fallback = head.Position if head.Name == "HumanoidRootPart" then fallback = fallback + Vector3.new(0, 1.5, 0) end local muzzle = tool:FindFirstChild("Muzzle", true) local handle = tool:FindFirstChild("Handle") local point = muzzle and muzzle:IsA("Attachment") and muzzle.WorldPosition or (handle and handle:IsA("BasePart") and handle.Position) or fallback if (point - fallback).Magnitude > 7 then return fallback end local delta = point - fallback if delta.Magnitude > 0.001 and Workspace:Raycast(fallback, delta, params) then return fallback end return point end local function shotDirection(origin, params) local util = modules.Util if util and type(util.AimDirection) == "function" then local ok, direction = pcall(util.AimDirection, origin) if ok and typeof(direction) == "Vector3" and direction.Magnitude > 0.001 then return direction.Unit end end local camera = Workspace.CurrentCamera if not camera then return nil end local hit = Workspace:Raycast(camera.CFrame.Position, camera.CFrame.LookVector * 1000, params) local point = hit and hit.Position or camera.CFrame.Position + camera.CFrame.LookVector * 1000 local delta = point - origin return delta.Magnitude > 0.001 and delta.Unit or camera.CFrame.LookVector end -- Original numeric solver. Coefficients are in ascending powers. local function finite(x) return type(x) == "number" and x == x and math.abs(x) < math.huge end local function polynomialValue(c, x) local y = c[#c] for i = #c - 1, 1, -1 do y = y * x + c[i] end return y end local function polynomialScale(c, x) local y = math.abs(c[#c]) for i = #c - 1, 1, -1 do y = y * math.abs(x) + math.abs(c[i]) end return y end local function polynomialRoots(c, lo, hi) while #c > 1 and c[#c] == 0 do table.remove(c) end local magnitude = 0 for _, value in ipairs(c) do magnitude = math.max(magnitude, math.abs(value)) end if magnitude == 0 or #c == 1 then return {} end for i = 1, #c do c[i] = c[i] / magnitude end if #c == 2 then local root = -c[1] / c[2] return root >= lo and root <= hi and {root} or {} end local derivative = {} for i = 2, #c do derivative[i - 1] = (i - 1) * c[i] end local boundaries = {lo} for _, value in ipairs(polynomialRoots(derivative, lo, hi)) do if value > lo and value < hi then table.insert(boundaries, value) end end table.insert(boundaries, hi) table.sort(boundaries) local roots = {} local function add(root) for _, existing in ipairs(roots) do if math.abs(existing - root) < 1e-8 then return end end table.insert(roots, root) end for _, x in ipairs(boundaries) do if math.abs(polynomialValue(c, x)) <= 1e-12 * math.max(1e-30, polynomialScale(c, x)) then add(x) end end for i = 1, #boundaries - 1 do local a, b = boundaries[i], boundaries[i + 1] local fa, fb = polynomialValue(c, a), polynomialValue(c, b) if (fa < 0 and fb > 0) or (fa > 0 and fb < 0) then for _ = 1, 44 do local middle = (a + b) * 0.5 local fm = polynomialValue(c, middle) if (fa < 0 and fm < 0) or (fa > 0 and fm > 0) then a, fa = middle, fm else b = middle end end add((a + b) * 0.5) end end table.sort(roots) return roots end local function intercepts(origin, target, velocity, speed, gravity, lifetime, targetAcceleration) if not finite(speed) or speed <= 0 or not finite(lifetime) or lifetime <= 0 then return {} end targetAcceleration = targetAcceleration or Vector3.zero local relativeGravity = gravity - targetAcceleration local offset = target - origin if offset.Magnitude < 0.001 then return {} end local c = { offset:Dot(offset), 2 * offset:Dot(velocity), velocity:Dot(velocity) - offset:Dot(relativeGravity) - speed * speed, -velocity:Dot(relativeGravity), 0.25 * relativeGravity:Dot(relativeGravity), } for i = 1, #c do c[i] = c[i] * lifetime ^ (i - 1) if not finite(c[i]) then return {} end end local solutions = {} for _, x in ipairs(polynomialRoots(c, 0.000001 / lifetime, 1)) do local time = x * lifetime local launch = offset / time + velocity - 0.5 * relativeGravity * time if finite(launch.Magnitude) and launch.Magnitude > 0 and math.abs(launch.Magnitude - speed) <= math.max(0.0001, speed * 0.00001) then table.insert(solutions, { time = time, direction = launch.Unit, impact = target + velocity * time + 0.5 * targetAcceleration * time * time, }) end end return solutions end local function parameters(tuning, charge) local minimum = tonumber(tuning.speedMin or tuning.speed) or 120 local maximum = tonumber(tuning.speedMax or tuning.speed) or minimum local speed = minimum + (maximum - minimum) * charge -- Hitscan: zero gravity so there is no drop; combined with zero target -- velocity in leadVelocity, the solve points straight at the current part. local gravity = aimHitscan and Vector3.zero or Vector3.new(0, -(tonumber(tuning.gravity) or 55), 0) return speed, gravity, tonumber(tuning.radius) or 0.3 end local function trace(origin, direction, speed, gravity, duration, params, radius, collect) local position, velocity = origin, direction * speed local points = collect and {origin} or nil local age, traveled = 0, 0 while age < duration - 1e-7 do local dt = math.min(Config.CastStep, duration - age) local delta = velocity * dt + 0.5 * gravity * dt * dt if traveled + delta.Magnitude > Config.MaxTravel then return points, nil, true end local hit if delta.Magnitude > 0.0001 then if radius > 0 then hit = Workspace:Spherecast(position, radius, delta, params) else hit = Workspace:Raycast(position, delta, params) end end if hit then if points then table.insert(points, position + delta.Unit * hit.Distance) end return points, hit, false end position = position + delta velocity = velocity + gravity * dt traveled = traveled + delta.Magnitude age = age + dt if points then table.insert(points, position) end end return points, nil, false end -- Landing is a bounded estimate on nearby, nearly level static ground. A ledge, -- moving platform or slope keeps the airborne model instead of inventing a floor. local function estimateLanding(record, velocity, targetGravity) local root, humanoid = record.root, record.humanoid local standingHeight = root.Size.Y * 0.5 + math.max(0, humanoid.HipHeight) if humanoid.RigType == Enum.HumanoidRigType.R6 then local leg = record.model:FindFirstChild("Left Leg") or record.model:FindFirstChild("Right Leg") if not leg or not leg:IsA("BasePart") then return nil end standingHeight = standingHeight + leg.Size.Y end local excluded, seen = {visuals}, {[visuals] = true} local function exclude(model) if model and not seen[model] then seen[model] = true; table.insert(excluded, model) end end exclude(record.model) exclude(player.Character) for _, other in ipairs(Players:GetPlayers()) do exclude(other.Character) end for model in pairs(records) do exclude(model) end local params = RaycastParams.new() params.FilterType = Enum.RaycastFilterType.Exclude params.FilterDescendantsInstances = excluded params.IgnoreWater, params.RespectCanCollide = true, true params.CollisionGroup = root.CollisionGroup local rootPosition = root.Position local function groundAt(x, z) local hit = Workspace:Raycast(Vector3.new(x, rootPosition.Y + 1, z), Vector3.new(0, -192, 0), params) if not hit or hit.Normal.Y < 0.98 then return nil end if hit.Instance:IsA("BasePart") and not hit.Instance.Anchored then return nil end return hit.Position.Y end local firstGround = groundAt(rootPosition.X, rootPosition.Z) if firstGround == nil then return nil end local clearance = rootPosition.Y - firstGround - standingHeight if clearance < -0.5 then return nil end local landingTime = (velocity.Y + math.sqrt(velocity.Y * velocity.Y + 2 * targetGravity * math.max(0, clearance))) / targetGravity if not finite(landingTime) or landingTime < 0 or landingTime > Config.MaxLifetime + 1 then return nil end local lastGround = groundAt(rootPosition.X + velocity.X * landingTime, rootPosition.Z + velocity.Z * landingTime) if lastGround == nil or math.abs(lastGround - firstGround) > 0.5 then return nil end -- Recompute for the checked landing surface; the small allowed height change -- limits extrapolation error without tracing a whole character trajectory. clearance = rootPosition.Y - lastGround - standingHeight if clearance < -0.5 then return nil end landingTime = (velocity.Y + math.sqrt(velocity.Y * velocity.Y + 2 * targetGravity * math.max(0, clearance))) / targetGravity return landingTime, lastGround + standingHeight + record.part.Position.Y - rootPosition.Y end local function targetMotion(record, velocity) local position, rootPosition = record.part.Position, record.root.Position local humanoid = record.humanoid local state = humanoid and humanoid:GetState() local targetGravity = Workspace.Gravity local now = os.clock() local cached = record.jumpMotion if cached and now - cached.sampledAt < 0.05 and cached.root == record.root and cached.part == record.part and cached.position == position and cached.rootPosition == rootPosition and cached.velocity == velocity and cached.state == state and cached.gravity == targetGravity and cached.enabled == Config.JumpPrediction then return cached end local motion = { position = position, rootPosition = rootPosition, velocity = velocity, acceleration = Vector3.zero, root = record.root, part = record.part, sampledAt = now, state = state, gravity = targetGravity, enabled = Config.JumpPrediction, } if not aimHitscan and Config.JumpPrediction and humanoid and finite(targetGravity) and targetGravity > 0 and (state == Enum.HumanoidStateType.Jumping or state == Enum.HumanoidStateType.Freefall) then -- Skipped for hitscan: an instant raycast has nothing to lead, so we aim -- the target's current position rather than a predicted landing. motion.acceleration = Vector3.new(0, -targetGravity, 0) motion.landingTime, motion.landingY = estimateLanding(record, velocity, targetGravity) end record.jumpMotion = motion return motion end local function motionIntercepts(origin, motion, speed, gravity, lifetime, lead) lead = finite(lead) and math.max(0, lead) or 0 local solutions = {} local remainingAirTime = motion.landingTime and math.max(0, motion.landingTime - lead) or lifetime if remainingAirTime > 0 then local position = motion.position + motion.velocity * lead + 0.5 * motion.acceleration * lead * lead local velocity = motion.velocity + motion.acceleration * lead solutions = intercepts(origin, position, velocity, speed, gravity, math.min(lifetime, remainingAirTime), motion.acceleration) end if motion.landingTime then local velocity = Vector3.new(motion.velocity.X, 0, motion.velocity.Z) local position = Vector3.new(motion.position.X, motion.landingY, motion.position.Z) + velocity * lead for _, solution in ipairs(intercepts(origin, position, velocity, speed, gravity, lifetime)) do if solution.time + lead >= motion.landingTime - 0.00001 then local duplicate = false for _, existing in ipairs(solutions) do if math.abs(solution.time - existing.time) < 0.00001 then duplicate = true; break end end if not duplicate then table.insert(solutions, solution) end end end end table.sort(solutions, function(a, b) return a.time < b.time end) return solutions end -- Strafe-aware target velocity. Smooths the raw physics velocity (kills the -- single-frame jitter behind small misses on straight runs) and tracks heading -- consistency: hold a direction and confidence -> 1 so we lead fully; reverse and -- confidence collapses so the lead folds back toward the target's current -- position (right after a juke their next step is a coin flip), then ramps back -- up as they commit. Horizontal only -- vertical stays raw for the jump model. local function leadVelocity(record, raw) if aimHitscan then record.strafe = nil; return Vector3.zero end -- no lead for hitscan if not Config.StrafePrediction then record.strafe = nil; return raw end local horizontal = Vector3.new(raw.X, 0, raw.Z) local now = os.clock() local s = record.strafe if not s then record.strafe = {smooth = horizontal, t = now, conf = 1, lead = horizontal} return Vector3.new(horizontal.X, raw.Y, horizontal.Z) end local dt = now - s.t if dt < 0.006 then return Vector3.new(s.lead.X, raw.Y, s.lead.Z) end local tau = tonumber(Config.StrafeTau) or 0.09 local alpha = math.clamp(dt / (dt + tau), 0, 1) local align = 1 if horizontal.Magnitude > 1 and s.smooth.Magnitude > 1 then align = horizontal.Unit:Dot(s.smooth.Unit) end local target = math.clamp((align + 0.25) / 1.25, 0, 1) local conf = target < s.conf and target or (s.conf + alpha * (target - s.conf)) local smooth = s.smooth:Lerp(horizontal, alpha) local lead = smooth * conf s.smooth, s.t, s.conf, s.lead = smooth, now, conf, lead return Vector3.new(lead.X, raw.Y, lead.Z) end local function solveRecord(record, origin, speed, gravity) if not record.model.Parent or not record.part.Parent or not record.root.Parent or not isEnemy(record.model, record.owner) then return {} end local rawVelocity = record.root.AssemblyLinearVelocity if not finite(rawVelocity.Magnitude) or rawVelocity.Magnitude > 1000 then return {} end local velocity = leadVelocity(record, rawVelocity) local motion = targetMotion(record, velocity) local solutions = motionIntercepts(origin, motion, speed, gravity, Config.MaxLifetime, Config.ExtraLeadSeconds) if Config.PreferHighArc then local reverse = {} for i = #solutions, 1, -1 do table.insert(reverse, solutions[i]) end return reverse end return solutions end local function selectTarget(origin, tuning, speed, gravity, radius, force, context) local camera = Workspace.CurrentCamera if not camera then selected = nil; return nil end local now = os.clock() if not force and now - selectionTime < Config.SelectInterval then return selected end selectionTime = now local range = math.min(Config.MaxDistance, tonumber(tuning.range) or Config.MaxDistance) local function check(record) if not record.part.Parent or not isEnemy(record.model, record.owner) or (record.part.Position - origin).Magnitude > range then return nil end if Config.SilentAim then local point, onScreen = camera:WorldToViewportPoint(record.part.Position) if not onScreen or point.Z <= 0 or (Vector2.new(point.X, point.Y) - camera.ViewportSize * 0.5).Magnitude > Config.FOVRadius then return nil end end local params = exclusions(record.model, context) for _, solution in ipairs(solveRecord(record, origin, speed, gravity)) do local pitch = math.asin(math.clamp(solution.direction.Y, -1, 1)) if pitch >= math.rad(-80) and pitch <= math.rad(78) then local _, hit, exhausted = trace(origin, solution.direction, speed, gravity, solution.time, params, radius, false) if not hit and not exhausted then return {record = record, solution = solution} end end end return nil end -- FOV is an acquisition rule. Ballistic camera elevation must not break a draw lock. if selected then local retained = check(selected.record) if retained then selected = retained; return selected end end local center = camera.ViewportSize * 0.5 local candidates = {} for _, record in pairs(records) do if record.part.Parent and isEnemy(record.model, record.owner) then local projected, onScreen = camera:WorldToViewportPoint(record.part.Position) local screenDistance = (Vector2.new(projected.X, projected.Y) - center).Magnitude local distance = (record.part.Position - origin).Magnitude if onScreen and projected.Z > 0 and screenDistance <= Config.FOVRadius and distance <= range then table.insert(candidates, {record = record, score = screenDistance}) end end end table.sort(candidates, function(a, b) return a.score < b.score end) selected = nil for i = 1, math.min(#candidates, Config.MaxCandidates) do local choice = check(candidates[i].record) if choice then selected = choice; return choice end end return nil end local function allowedToAim() if renderFailed or not windowFocused or not Config.Aim or UIS:GetFocusedTextBox() or GuiService.MenuIsOpen or (panel.Visible and panelHovered) then return false end if not (drawing or (not nativeDraw and heldFallback)) then -- Instant-fire weapons never "draw"; allow silent targeting/preview while equipped. local _, _, _, _, model = bowInfo() if not (model == "instant" and Config.SilentAim) then return false end end local character = player.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") return humanoid ~= nil and humanoid.Health > 0 and attribute(character, player, "Alive") ~= false end -- Make the camera's 1000-stud endpoint lie on the desired muzzle ray. local function cameraDirection(origin, direction, cameraPosition) local offset = cameraPosition - origin local along = offset:Dot(direction) local perpendicularSquared = math.max(0, offset:Dot(offset) - along * along) local distance = along + math.sqrt(math.max(1, 1000 * 1000 - perpendicularSquared)) return (origin + direction * distance - cameraPosition).Unit end local function setView(direction) local camera = Workspace.CurrentCamera if not camera or not finite(direction.Magnitude) or direction.Magnitude < 0.001 then return end local yaw = math.atan2(-direction.X, -direction.Z) local pitch = math.clamp(math.asin(math.clamp(direction.Y, -1, 1)), math.rad(-80), math.rad(78)) local nativeCamera = modules.Camera if nativeCamera and type(nativeCamera.SetLook) == "function" then pcall(nativeCamera.SetLook, yaw, pitch) end camera.CFrame = CFrame.new(camera.CFrame.Position) * CFrame.fromEulerAnglesYXZ(pitch, yaw, 0) end applyAim = function(forcedCharge, forceCheck, context) if not active or not allowedToAim() then return nil end local tool, tuning = bowInfo() if not tool or not allowedToAim() then return nil end context = context or exclusionContext() local charge = forcedCharge if charge == nil then charge = chargeFor(tuning) end local speed, gravity, radius = parameters(tuning, charge) local params = exclusions(nil, context) local origin = shotOrigin(tool, params) if not origin then return nil end local choice = selectTarget(origin, tuning, speed, gravity, radius, forceCheck, context) if not choice then return nil end if Config.SilentAim then return bowAdaptersReady and choice or nil end local camera = Workspace.CurrentCamera local originalView = camera.CFrame local function reject() setView(originalView.LookVector) camera.CFrame = originalView selected = nil return nil end local solution -- Re-evaluate because the game's third-person ShotOrigin depends on camera direction. for _ = 1, 3 do origin = shotOrigin(tool, params) if not origin then return reject() end local roots = solveRecord(choice.record, origin, speed, gravity) solution = roots[1] if not solution then return reject() end -- Preserve the collision-approved arc if several roots exist. for _, candidate in ipairs(roots) do if math.abs(candidate.time - choice.solution.time) < math.abs(solution.time - choice.solution.time) then solution = candidate end end local launchPitch = math.asin(math.clamp(solution.direction.Y, -1, 1)) if launchPitch < math.rad(-80) or launchPitch > math.rad(78) then return reject() end setView(cameraDirection(origin, solution.direction, camera.CFrame.Position)) local actual = shotDirection(origin, params) if actual and actual:Dot(solution.direction) < 0.999999 then local corrected = camera.CFrame.LookVector + solution.direction - actual if corrected.Magnitude > 0.001 then setView(corrected.Unit) end end end local finalOrigin = shotOrigin(tool, params) if not finalOrigin then return reject() end local actualDirection = shotDirection(finalOrigin, params) if not actualDirection then return reject() end local endpoint = finalOrigin + actualDirection * speed * solution.time + gravity * (0.5 * solution.time * solution.time) local size = choice.record.part.Size local tolerance = radius + math.max(0.25, math.min(size.X, size.Y, size.Z) * 0.35) if (endpoint - solution.impact).Magnitude > tolerance then return reject() end if forceCheck or not choice.finalCheck or os.clock() - choice.finalCheck >= Config.SelectInterval then local _, hit, exhausted = trace(finalOrigin, actualDirection, speed, gravity, solution.time, exclusions(choice.record.model, context), radius, false) if hit or exhausted then return reject() end choice.finalCheck = os.clock() end choice.solution = solution return choice end local function clearRecordShot(record, origin, tuning, charge, context) if not record or not record.part.Parent or not isEnemy(record.model, record.owner) then return nil end if (record.part.Position - origin).Magnitude > math.min(Config.MaxDistance, tonumber(tuning.range) or Config.MaxDistance) then return nil end local speed, gravity, radius = parameters(tuning, charge) for _, solution in ipairs(solveRecord(record, origin, speed, gravity)) do local pitch = math.asin(math.clamp(solution.direction.Y, -1, 1)) if pitch >= math.rad(-80) and pitch <= math.rad(78) then local _, hit, exhausted = trace(origin, solution.direction, speed, gravity, solution.time, exclusions(record.model, context), radius, false) if not hit and not exhausted then return {record = record, solution = solution} end end end return nil end local function findShot(tool, tuning, charge, context) context = context or exclusionContext() local origin = shotOrigin(tool, exclusions(nil, context)) if not origin then return nil end local speed, gravity, radius = parameters(tuning, charge) return selectTarget(origin, tuning, speed, gravity, radius, true, context) end stopAuto = function(reason) local owned = autoOwned autoOwned = nil if owned then -- Cancel before releasing the native input; a release alone would fire. owned.bufferedAt = nil if owned.drawing then local ok, err = pcall(owned.CancelDraw, owned) if not ok or owned.drawing then owned.drawing = false -- Never turn a failed cancellation into a release shot. if not ok then warn("[Kingfisher] Native draw cancellation failed: " .. tostring(err)) end end end owned.m1Down = false local equipped = player.Character and player.Character:FindFirstChildOfClass("Tool") if owned.ctx and owned.ctx.tool == equipped and modules.Controller then pcall(modules.Controller.Dispatch, "Primary", false) end end autoNote = "Auto: " .. (Config.AutoBow and (reason or "OFF") or "OFF") end table.insert(destructors, function() stopAuto("OFF") end) local bowHookCleanup installBowAdapters = function() if not active or bowHookCleanup then return end local bow, util, controller = modules.Bow, modules.Util, modules.Controller -- No longer gated on nativeDraw: the assist redirect and instant auto-fire -- work for gun/throw weapons that never raise the bow's native Draw event. if not bow or not util or not controller or type(bow.Update) ~= "function" or type(bow.Fire) ~= "function" or type(bow.CancelDraw) ~= "function" or type(bow.Charge) ~= "function" or type(util.AssistDirection) ~= "function" or type(controller.Dispatch) ~= "function" then return end local oldUpdate, oldFire, oldAssist = bow.Update, bow.Fire, util.AssistDirection local blockedAutoShot = {} local updateWrapper, fireWrapper, assistWrapper updateWrapper = function(self, ...) if active and self.ctx then local equipped = player.Character and player.Character:FindFirstChildOfClass("Tool") if self.ctx.tool == equipped then autoHandler = self end end return oldUpdate(self, ...) end fireWrapper = function(self, ...) local equipped = player.Character and player.Character:FindFirstChildOfClass("Tool") if not active or not self.drawing or not self.ctx or self.ctx.tool ~= equipped then return oldFire(self, ...) end local assisted = Config.Aim and windowFocused and not renderFailed and not UIS:GetFocusedTextBox() and not GuiService.MenuIsOpen and not panel.Visible local charge = self:Charge() local automatic = autoOwned == self if automatic then autoReleaseResult = false end local choice if assisted then if Config.SilentAim then choice = findShot(equipped, self.tuning, charge) else choice = applyAim(charge, true) end end if automatic and not choice then autoReleaseResult = false stopAuto("Waiting for a clear shot") return end local thread = coroutine.running() local previous = firingContexts[thread] local shotScope if assisted and (Config.SilentAim or automatic) and choice then shotScope = {record = choice.record, tuning = self.tuning, charge = charge, tool = equipped, automatic = automatic} firingContexts[thread] = shotScope else firingContexts[thread] = nil end local result = table.pack(pcall(oldFire, self, ...)) firingContexts[thread] = previous if not result[1] and result[2] == blockedAutoShot then self.bufferedAt = nil pcall(self.CancelDraw, self) self.m1Down = false autoOwned, autoReleaseResult = nil, false autoNote = "Auto: canceled; shot path changed" return end if not result[1] then if automatic then stopAuto("Native release failed") Config.AutoBow = false autoNote = "Auto: ERROR; see output and re-enable" end error(result[2], 0) end if automatic then autoReleaseResult = shotScope ~= nil and shotScope.used == true if not autoReleaseResult then autoOwned = nil; autoNote = "Auto: native release canceled" end end return table.unpack(result, 2, result.n) end assistWrapper = function(origin, direction, preservePitch, ...) local scope = firingContexts[coroutine.running()] local equipped = player.Character and player.Character:FindFirstChildOfClass("Tool") if scope and scope.automatic and (not active or renderFailed or not windowFocused or not Config.Aim or not Config.AutoBow or panel.Visible or GuiService.MenuIsOpen or UIS:GetFocusedTextBox() or scope.tool ~= equipped or scope.tool.Parent ~= player.Character or typeof(origin) ~= "Vector3") then error(blockedAutoShot, 0) end if active and not renderFailed and Config.Aim and scope and (Config.SilentAim or scope.automatic) and scope.tool == equipped and scope.tool.Parent == player.Character and typeof(origin) == "Vector3" then -- The bow supplies its actual muzzle origin here, after its Release event. local ok, choice = pcall(function() return clearRecordShot(scope.record, origin, scope.tuning, scope.charge, exclusionContext()) end) if ok and choice then scope.used = true; return choice.solution.direction end if scope.automatic then error(blockedAutoShot, 0) end end -- Generic assist for any projectile weapon fired outside the bow's draw -- scope (crossbow, musket, flintlock, blunderbuss, knives, sling, etc.). -- The handler hands us its true muzzle origin here, so redirect the shot -- the game is about to send. Active in SILENT mode, or during an auto tap. if not scope and active and not renderFailed and Config.Aim and (Config.SilentAim or instantAutoFiring) and windowFocused and not GuiService.MenuIsOpen and not UIS:GetFocusedTextBox() and typeof(origin) == "Vector3" then local gtool, gtuning, _, _, gmodel = bowInfo() if gtool and gtool.Parent == player.Character then local gcharge = gmodel == "charge" and (select(1, chargeFor(gtuning))) or 1 local gspeed, ggravity, gradius = parameters(gtuning, gcharge) local okSel, gchoice = pcall(selectTarget, origin, gtuning, gspeed, ggravity, gradius, true, exclusionContext()) if okSel and gchoice and gchoice.solution then return gchoice.solution.direction end end end return oldAssist(origin, direction, preservePitch, ...) end local function restore() if bow.Update == updateWrapper then bow.Update = oldUpdate end if bow.Fire == fireWrapper then bow.Fire = oldFire end if util.AssistDirection == assistWrapper then util.AssistDirection = oldAssist end end local ok, err = pcall(function() bow.Update, bow.Fire, util.AssistDirection = updateWrapper, fireWrapper, assistWrapper end) if not ok then pcall(restore) autoNote = "Native bow adapter unavailable" warn("[Kingfisher] Bow adapter could not be installed: " .. tostring(err)) return end bowHookCleanup = restore bowAdaptersReady = true table.insert(destructors, function() table.clear(firingContexts) autoHandler = nil bowAdaptersReady = false restore() end) end installBowAdapters() local function readyToRelease(charge, choice, tuning, weaponId) if not choice then return false end if charge >= 0.995 then return true end if not Config.SmartCharge or charge < Config.AutoMinCharge or choice.solution.time > Config.AutoMaxFlight then return false end local maximum = tonumber(tuning.damage) or 0 local minimum = tonumber(tuning.damageMin) or maximum local damage = minimum + (maximum - minimum) * charge local combat = modules.Combat if combat and type(combat.DrawnShot) == "function" then local ok, amount = pcall(combat.DrawnShot, tuning, charge) if ok and type(amount) == "number" then damage = amount end end if modules.Util and type(modules.Util.ItemBonus) == "function" then local ok, bonus = pcall(modules.Util.ItemBonus, weaponId) if ok and finite(bonus) and bonus > 0 then damage = damage * bonus end end -- This is a base-damage estimate; armor and server-side modifiers are not known. local humanoid = choice.record.humanoid return humanoid ~= nil and humanoid.Health > 0 and damage >= humanoid.Health end -- Auto-fire for instant weapons (crossbow / musket / flintlock / blunderbuss / -- knives / sling / bolas / chakram). There is no draw to manage: when a clear -- shot exists we tap the native Primary input and let the generic assist above -- redirect the shot onto the target. Paced by the weapon's own fire interval. local function updateAutoInstant(now, tool, tuning, weaponId) if autoOwned then stopAuto("Switched to instant weapon") end local character = player.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") if not active or renderFailed or not Config.AutoBow or not Config.Aim or not bowAdaptersReady or not windowFocused or panel.Visible or GuiService.MenuIsOpen or UIS:GetFocusedTextBox() or not tool or not humanoid or humanoid.Health <= 0 or attribute(character, player, "Alive") == false or UIS:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then if Config.AutoBow then autoNote = "Auto: paused; hide menu, release LMB" end return end if now < autoNext then return end local util = modules.Util if util and type(util.CanAct) == "function" then local ok, canAct = pcall(util.CanAct) if not ok or not canAct then autoNote = "Auto: waiting until weapon can act"; autoNext = now + 0.1; return end end if util and type(util.IsMouseUnlocked) == "function" then local ok, unlocked = pcall(util.IsMouseUnlocked) if ok and unlocked then autoNote = "Auto: paused: game menu open"; return end end if tool:GetAttribute("Reloading") == true then autoNote = "Auto: reloading"; autoNext = now + 0.1; return end local choice = findShot(tool, tuning, 1) if not choice then autoNote = "Auto: no clear target in FOV"; autoNext = now + 0.05; return end selected, selectionTime = choice, -math.huge instantAutoFiring = true local ok = pcall(modules.Controller.Dispatch, "Primary", true) pcall(modules.Controller.Dispatch, "Primary", false) instantAutoFiring = false autoNote = ok and "Auto: firing" or "Auto: dispatch failed" local interval = tonumber(tuning.fireInterval) or tonumber(tuning.cooldown) or 0.3 autoNext = now + math.max(interval + 0.02, Config.AutoInterval) end local function updateAutoBow(now, tool, tuning, weaponId, model) if model == "instant" then return updateAutoInstant(now, tool, tuning, weaponId) end local character = player.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") local blocked = not active or renderFailed or not Config.AutoBow or not Config.Aim or not bowAdaptersReady or not windowFocused or panel.Visible or GuiService.MenuIsOpen or UIS:GetFocusedTextBox() or not tool or not humanoid or humanoid.Health <= 0 or attribute(character, player, "Alive") == false or UIS:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) if blocked then if autoOwned then stopAuto("Paused") elseif Config.AutoBow then autoNote = "Auto: paused; hide menu, release LMB" end return end local handler = autoHandler if not handler or not handler.ctx or handler.ctx.tool ~= tool then if autoOwned then stopAuto("Weapon changed") end autoNote = "Auto: waiting for native bow; re-equip" return end if autoOwned and autoOwned ~= handler then stopAuto("Weapon changed") end if now < autoNext then return end autoNext = now + Config.AutoInterval local util = modules.Util if type(util.CanAct) == "function" then local ok, canAct = pcall(util.CanAct) if not ok or not canAct then stopAuto("Waiting until bow can act"); return end end if type(util.IsMouseUnlocked) == "function" then local ok, unlocked = pcall(util.IsMouseUnlocked) if ok and unlocked then stopAuto("Paused: game menu open"); return end end if not autoOwned then if handler.drawing then autoNote = "Auto: manual draw"; return end local plan = findShot(tool, tuning, 1) if not plan then autoNote = "Auto: no clear target in FOV"; return end autoOwned, autoStarted, autoLastClear = handler, now, now local ok = pcall(modules.Controller.Dispatch, "Primary", true) if not ok or not handler.drawing then stopAuto("Waiting for cooldown/ammo") autoNext = now + 0.2 return end selected = plan selectionTime = -math.huge end if not handler.drawing then stopAuto("Ready"); return end local charge = math.clamp(handler:Charge(), 0, 1) local choice = findShot(tool, tuning, charge) if choice then autoLastClear = now end if not choice and now - autoLastClear > Config.AutoLostTargetGrace then -- A low-charge bow may be out of range; keep drawing if full charge still reaches. if not findShot(tool, tuning, 1) then stopAuto("Target lost or blocked"); return end autoLastClear = now end if now - autoStarted > math.max(Config.AutoMaxHold, (tuning.drawTime or 1) + 0.5) then stopAuto("Charge timed out") return end if readyToRelease(charge, choice, tuning, weaponId) then autoReleaseResult = nil local ok, err = pcall(modules.Controller.Dispatch, "Primary", false) if not ok then stopAuto("Release failed"); warn("[Kingfisher] Auto release: " .. tostring(err)); return end if autoReleaseResult == false then autoNext = now + 0.2; return end if handler.drawing then stopAuto("Release was not accepted"); return else autoOwned = nil end autoNote = "Auto: released; waiting for cooldown" autoNext = now + 0.1 else autoNote = string.format("Auto: charging %d%% | %s", math.floor(charge * 100), choice and "clear shot" or "waiting for range") end end local trajectoryParts = {} local function trajectoryPart() return make("Part", { Name = "Arc", Anchored = true, CanCollide = false, CanTouch = false, CanQuery = false, CastShadow = false, Material = Enum.Material.Neon, Transparency = 1, Size = Vector3.new(0.065, 0.065, 1), }, visuals) end for _ = 1, 72 do table.insert(trajectoryParts, trajectoryPart()) end local impactMarker = make("Part", { Name = "PredictedImpact", Shape = Enum.PartType.Ball, Size = Vector3.new(0.45, 0.45, 0.45), Anchored = true, CanCollide = false, CanTouch = false, CanQuery = false, CastShadow = false, Material = Enum.Material.Neon, Transparency = 1, }, visuals) local function hideTrajectory() for _, part in ipairs(trajectoryParts) do part.Transparency = 1 end impactMarker.Transparency = 1 end local function displayTrajectory(points, blocked) if not points or #points < 2 then hideTrajectory(); return end local count = math.min(#trajectoryParts, #points - 1) local color = blocked and Color3.fromRGB(255, 125, 83) or Color3.fromRGB(67, 220, 208) for i, part in ipairs(trajectoryParts) do if i <= count then local a = points[math.floor((i - 1) * (#points - 1) / count) + 1] local b = points[math.floor(i * (#points - 1) / count) + 1] local distance = (b - a).Magnitude if distance > 0.001 then part.Size = Vector3.new(0.065, 0.065, distance) part.CFrame = CFrame.lookAt((a + b) * 0.5, b) part.Color, part.Transparency = color, 0.12 else part.Transparency = 1 end else part.Transparency = 1 end end impactMarker.Position = points[#points] impactMarker.Color, impactMarker.Transparency = color, 0.15 end connect(UIS.InputBegan, function(input, processed) if renderFailed or processed or UIS:GetFocusedTextBox() then return end if input.UserInputType == Enum.UserInputType.MouseButton1 and not nativeDraw and not (panel.Visible and panelHovered) then local tool, tuning = bowInfo() if tool then heldFallback = true drawStart, drawDuration = os.clock(), tuning.drawTime or 1 selected, selectionTime = nil, -math.huge end end end) connect(UIS.InputEnded, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then local ok, err = true, nil if not nativeDraw and heldFallback then ok, err = pcall(applyAim, nil, true) end heldFallback = false if not nativeDraw then selected = nil end if not ok then warn("[Kingfisher] Estimated release adjustment failed: " .. tostring(err)) end end end) connect(UIS.WindowFocusReleased, function() windowFocused = false stopAuto("Paused: window unfocused") drawing, heldFallback, selected = false, false, nil dragging = false end) connect(UIS.WindowFocused, function() windowFocused = true end) connect(player.CharacterAdded, function() stopAuto("Respawned") autoHandler = nil drawing, heldFallback, selected, lastTool = false, false, nil, nil selectionTime = -math.huge end) local function mathTests() local zero = Vector3.zero local function test(name, target, velocity, speed, gravity, lifetime, expected) local roots = intercepts(zero, target, velocity, speed, gravity, lifetime) assert(#roots == #expected, name .. ": wrong root count " .. tostring(#roots)) for i, solution in ipairs(roots) do assert(math.abs(solution.time - expected[i]) < 0.001, name .. ": wrong time") local endpoint = solution.direction * speed * solution.time + gravity * (0.5 * solution.time ^ 2) assert((endpoint - target - velocity * solution.time).Magnitude < 0.01, name .. ": endpoint miss") end end test("linear", Vector3.new(100, 0, 0), Vector3.new(10, 0, 0), 50, zero, 10, {2.5}) test("outrunning", Vector3.new(100, 0, 0), Vector3.new(60, 0, 0), 50, zero, 10, {}) test("two arcs", Vector3.new(100, 0, 0), zero, 50, Vector3.new(0, -10, 0), 12, {2.0430964, 9.7890631}) test("tangent", Vector3.new(250, 0, 0), zero, 50, Vector3.new(0, -10, 0), 12, {7.0710678}) test("unreachable", Vector3.new(251, 0, 0), zero, 50, Vector3.new(0, -10, 0), 12, {}) test("lifetime", Vector3.new(100, 0, 0), zero, 50, Vector3.new(0, -10, 0), 5, {2.0430964}) test("coincident", zero, zero, 50, zero, 5, {}) test("zero speed", Vector3.new(100, 0, 0), zero, 0, zero, 5, {}) print("[Kingfisher] 8 ballistic tests passed.") return true end local nextRefresh, nextTrajectory, nextUI = 0, 0, 0 local function render() if not active or renderFailed then return end local now = os.clock() local camera = Workspace.CurrentCamera if not camera then return end if now >= nextRefresh then refreshTargets(); nextRefresh = now + Config.TargetRefresh end local tool, tuning, id, weaponKind, weaponModel = bowInfo() updateAutoBow(now, tool, tuning, id, weaponModel) local charge, isDrawing = 1, false local choice, castContext if tool then charge, isDrawing = chargeFor(tuning) if allowedToAim() then castContext = exclusionContext() choice = applyAim(nil, false, castContext) end else selected = nil end if not allowedToAim() then selected = nil end ring.Visible = Config.Aim and tool ~= nil and not GuiService.MenuIsOpen ring.Position = UDim2.fromOffset(camera.ViewportSize.X * 0.5, camera.ViewportSize.Y * 0.5) ring.Size = UDim2.fromOffset(Config.FOVRadius * 2, Config.FOVRadius * 2) aimDot.Visible = false if choice then local point, visible = camera:WorldToViewportPoint(choice.solution.impact) if visible then aimDot.Position = UDim2.fromOffset(point.X, point.Y); aimDot.Visible = true end end if now >= nextTrajectory then nextTrajectory = now + (isDrawing and Config.TrajectoryInterval or Config.IdleTrajectoryInterval) if tool and Config.Trajectory then castContext = castContext or exclusionContext() local params = exclusions(nil, castContext) local origin = shotOrigin(tool, params) local direction = choice and Config.SilentAim and choice.solution.direction or (origin and shotDirection(origin, params)) if direction then local speed, gravity, radius = parameters(tuning, charge) local duration = choice and choice.solution.time or Config.MaxLifetime local points, hit, exhausted = trace(origin, direction, speed, gravity, duration, params, radius, true) displayTrajectory(points, hit ~= nil or exhausted) else hideTrajectory() end else hideTrajectory() end end if now >= nextUI then nextUI = now + 0.1 saveConfig() -- debounced: writes only when a setting actually changed for key, item in pairs(buttons) do item.button.Text = item.caption .. (Config[key] and " ON" or " OFF") item.button.BackgroundColor3 = Config[key] and Color3.fromRGB(25, 69, 77) or Color3.fromRGB(60, 50, 54) end namesButton.Text = Config.Names and "NAMES ON" or "NAMES OFF" partButton.Text = Config.TargetPart == "Head" and "TARGET: HEAD" or "TARGET: TORSO" fovLabel.Text = string.format("AIM FOV: %d px", Config.FOVRadius) arcButton.Text = Config.PreferHighArc and "ARC: HIGH / LOB" or "ARC: LOW / FAST" modeButton.Text = Config.SilentAim and "AIM: SILENT" or "AIM: CAMERA" autoButton.Text = Config.AutoBow and "AUTO FIRE ON" or "AUTO FIRE OFF" smartButton.Text = Config.SmartCharge and "SMART CHARGE ON" or "SMART CHARGE OFF" jumpButton.Text = Config.JumpPrediction and "JUMP LEAD ON" or "JUMP LEAD OFF" recoilButton.Text = Config.NoRecoil and "NO RECOIL ON" or "NO RECOIL OFF" recoilButton.BackgroundColor3 = Config.NoRecoil and Color3.fromRGB(25, 69, 77) or Color3.fromRGB(32, 47, 58) spreadButton.Text = Config.NoSpread and "NO SPREAD ON" or "NO SPREAD OFF" spreadButton.BackgroundColor3 = Config.NoSpread and Color3.fromRGB(25, 69, 77) or Color3.fromRGB(32, 47, 58) flyButton.Text = Config.Fly and "FLY ON" or "FLY OFF" flyButton.BackgroundColor3 = Config.Fly and Color3.fromRGB(25, 69, 77) or Color3.fromRGB(32, 47, 58) speedButton.Text = Config.Speed and "SPEED ON" or "SPEED OFF" speedButton.BackgroundColor3 = Config.Speed and Color3.fromRGB(25, 69, 77) or Color3.fromRGB(32, 47, 58) jumpBoostButton.Text = Config.SuperJump and "JUMP ON" or "JUMP OFF" jumpBoostButton.BackgroundColor3 = Config.SuperJump and Color3.fromRGB(25, 69, 77) or Color3.fromRGB(32, 47, 58) modeButton.BackgroundColor3 = Config.SilentAim and Color3.fromRGB(25, 69, 77) or Color3.fromRGB(32, 47, 58) autoButton.BackgroundColor3 = Config.AutoBow and Color3.fromRGB(25, 69, 77) or Color3.fromRGB(32, 47, 58) autoLabel.Text = autoNote adapterLabel.Text = (nativeDraw and "Charge: native" or "Charge: estimated") .. (modules.Util and " | Origin: native" or " | Origin: fallback") for _, record in pairs(records) do local alive = record.root.Parent and isEnemy(record.model, record.owner) local distance = alive and (record.root.Position - camera.CFrame.Position).Magnitude or math.huge local enabled = Config.ESP and alive and distance <= Config.MaxDistance record.highlight.Enabled = enabled record.billboard.Enabled = enabled and Config.Names record.highlight.OutlineColor = choice and choice.record == record and Color3.fromRGB(255, 219, 103) or Color3.fromRGB(255, 146, 127) if enabled then record.label.Text = string.format("%s | %d HP | %d st", record.owner and record.owner.DisplayName or record.model.Name, math.max(0, math.floor(record.humanoid.Health)), math.floor(distance)) end end status.Text = tool and string.format("%s (%s) | %d%% %s", id or "?", weaponKind or "?", math.floor(charge * 100), weaponModel == "instant" and "ready" or (isDrawing and (nativeDraw and "draw" or "estimated") or "preview")) or "Equip a weapon (bow, crossbow, musket, knives, javelin...)" targetLabel.Text = choice and string.format("%s | %.2fs flight", choice.record.model.Name, choice.solution.time) or (allowedToAim() and "No clear, reachable target in FOV" or "Enable AIM; silent aim covers every weapon") end end if Config.RunMathTests then local ok, err = pcall(mathTests) if not ok then unload(); error(err) end end RunService:BindToRenderStep(binding, Enum.RenderPriority.Camera.Value + 3, function() local ok, err = pcall(render) if not ok then -- Keep the menu and its key binding alive so a failed feature cannot erase the UI. renderFailed = true stopAuto("Stopped after error") RunService:UnbindFromRenderStep(binding) drawing, heldFallback, selected = false, false, nil ring.Visible, aimDot.Visible = false, false hideTrajectory() for _, record in pairs(records) do record.highlight.Enabled = false record.billboard.Enabled = false end status.Visible, targetLabel.Visible, adapterLabel.Visible, autoLabel.Visible = false, false, false, false make("TextLabel", { Name = "RuntimeError", Position = UDim2.fromOffset(12, 241), Size = UDim2.fromOffset(318, 85), BackgroundTransparency = 1, Font = Enum.Font.Code, TextSize = 11, TextColor3 = Color3.fromRGB(255, 146, 127), TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, TextWrapped = true, Text = "Features stopped; rerun script.\n" .. tostring(err):sub(1, 160), }, content) setMenuVisible(true) warn("[Kingfisher] Features stopped after runtime error (menu stays available): " .. tostring(err)) end end) -- ============================================================================ -- Circle Strafe (+ auto-Fly) + on-screen HUD. -- Toggle-to-activate, isolated from the aim core. All character movement is -- client-side CFrame work: it replicates in Roblox, but it is also the most -- anticheat-visible thing here and Tribes' server movement checks are unknown -- (no server code in the dump). Edit KEYS below to rebind; tune Config.Circle*. -- ============================================================================ Config.CircleRadius = Config.CircleRadius or 6 -- studs from target (tight orbit) Config.CircleHeight = Config.CircleHeight or 2 -- hover height above target root Config.CircleSpeed = Config.CircleSpeed or 12.0 -- orbit rate (rad/s) Config.StrafeSmooth = Config.StrafeSmooth or 0.30 -- 0..1 move-toward (lower = smoother) Config.CircleRange = Config.CircleRange or 120 -- target acquisition range (studs) local KEYS = { Strafe = Enum.KeyCode.End, -- toggle: orbit / park behind target (auto-fly) Mode = Enum.KeyCode.B, -- tap: switch Orbit <-> Behind-Back } local toggles, orbitAngle, flying, platformStash = {}, 0, false, nil local function nearestEnemy(fromPos, maxRange) local best, bestDist for _, record in pairs(records) do local root = record.root if root and root.Parent and isEnemy(record.model, record.owner) and record.humanoid and record.humanoid.Health > 0 then local d = (root.Position - fromPos).Magnitude if d <= maxRange and (not bestDist or d < bestDist) then best, bestDist = record, d end end end return best end -- Ring visualizer (segmented neon circle on the ground under the target) ------ local RING_SEGMENTS = 28 local ringParts = {} for _ = 1, RING_SEGMENTS do ringParts[#ringParts + 1] = make("Part", { Name = "StrafeRing", Anchored = true, CanCollide = false, CanTouch = false, CanQuery = false, CastShadow = false, Material = Enum.Material.Neon, Size = Vector3.new(0.14, 0.14, 1), Transparency = 1, }, visuals) end local function hideRing() for _, p in ipairs(ringParts) do p.Transparency = 1 end end local function drawRing(center, radius, color) for i, p in ipairs(ringParts) do local a0, a1 = (i - 1) / RING_SEGMENTS * math.pi * 2, i / RING_SEGMENTS * math.pi * 2 local p0 = center + Vector3.new(math.cos(a0), 0, math.sin(a0)) * radius local p1 = center + Vector3.new(math.cos(a1), 0, math.sin(a1)) * radius p.Size = Vector3.new(0.14, 0.14, (p1 - p0).Magnitude) p.CFrame = CFrame.lookAt((p0 + p1) * 0.5, p1) p.Color, p.Transparency = color, 0.2 end end -- On-screen HUD: keybinds + active features ---------------------------------- local hud = make("Frame", { Name = "KFHud", AnchorPoint = Vector2.new(0, 1), Position = UDim2.new(0, 14, 1, -14), Size = UDim2.fromOffset(190, 104), BackgroundColor3 = Color3.fromRGB(15, 23, 30), BackgroundTransparency = 0.25, BorderSizePixel = 0, }, gui) make("UICorner", {CornerRadius = UDim.new(0, 7)}, hud) make("UIStroke", {Color = Color3.fromRGB(47, 83, 90), Thickness = 1}, hud) local function hudLine(y, size) return make("TextLabel", { Position = UDim2.fromOffset(10, y), Size = UDim2.new(1, -20, 0, size + 4), BackgroundTransparency = 1, Font = Enum.Font.Code, Text = "", TextSize = size, TextXAlignment = Enum.TextXAlignment.Left, TextColor3 = Color3.fromRGB(221, 231, 237), }, hud) end local hudTitle = hudLine(6, 13); hudTitle.Text = "KINGFISHER"; hudTitle.TextColor3 = Color3.fromRGB(87, 221, 211) local hudStrafe, hudMode = hudLine(26, 12), hudLine(44, 12) local hudSpread, hudActive = hudLine(62, 12), hudLine(82, 11) connect(UIS.InputBegan, function(input, processed) if processed or UIS:GetFocusedTextBox() then return end if input.KeyCode == KEYS.Strafe then toggles[KEYS.Strafe] = not toggles[KEYS.Strafe] elseif input.KeyCode == KEYS.Mode then Config.CircleStrafeMode = Config.CircleStrafeMode == "Orbit" and "BehindBack" or "Orbit" end end) -- No Spread (guns): spread is server-side AND the server validates the shot id, -- so juggling the id to chase a lucky seed just gets shots rejected. The robust -- route is the game's own aimed-spread -- a gun reports far less spread when -- aimed (musket ~0.25 deg vs 3.2 deg hip). So No Spread forces the equipped gun -- into the server's "aimed" state, WITHOUT zooming the camera, collapsing spread -- to near zero while shots register normally. local function installNoSpread() local Gun = modules.Gun if type(Gun) ~= "table" or type(Gun.Update) ~= "function" then return end local old = Gun.Update Gun.Update = function(self, ...) if active and Config.NoSpread and self and self.ctx and type(self.ctx.send) == "function" then self.aiming = true self.aimStart = self.aimStart or 0 if os.clock() - (self.__kfAimSent or 0) > 0.5 then self.__kfAimSent = os.clock() pcall(self.ctx.send, "Aim", {on = true, tool = self.ctx.tool}) end end return old(self, ...) end end installNoSpread() Config.FlySpeed = Config.FlySpeed or 60 -- fly studs/sec Config.SpeedBoost = Config.SpeedBoost or 32 -- extra studs/sec added along move input Config.JumpPower = Config.JumpPower or 130 -- Super Jump power local function stopFly(humanoid) if flying and humanoid and platformStash ~= nil then humanoid.PlatformStand = platformStash end flying, platformStash = false, nil end -- Super-jump stashes/restores jump power. (Speed is a positional nudge in the -- movement loop, not WalkSpeed, since the game overwrites WalkSpeed every frame.) local savedJP, savedUseJP, savedJH local function applyStatMods(humanoid) if not humanoid then return end if active and Config.SuperJump then if savedUseJP == nil then savedUseJP, savedJP, savedJH = humanoid.UseJumpPower, humanoid.JumpPower, humanoid.JumpHeight end humanoid.UseJumpPower = true humanoid.JumpPower = Config.JumpPower elseif savedUseJP ~= nil then humanoid.UseJumpPower, humanoid.JumpPower, humanoid.JumpHeight = savedUseJP, savedJP, savedJH savedUseJP = nil end end -- Free-fly: camera-relative WASD + space/shift, while PlatformStand holds physics local function manualFly(dt, root, humanoid) if not flying then platformStash = humanoid.PlatformStand; flying = true end humanoid.PlatformStand = true local cam = Workspace.CurrentCamera local move = Vector3.zero if cam then local cf = cam.CFrame if UIS:IsKeyDown(Enum.KeyCode.W) then move += cf.LookVector end if UIS:IsKeyDown(Enum.KeyCode.S) then move -= cf.LookVector end if UIS:IsKeyDown(Enum.KeyCode.D) then move += cf.RightVector end if UIS:IsKeyDown(Enum.KeyCode.A) then move -= cf.RightVector end if UIS:IsKeyDown(Enum.KeyCode.Space) then move += Vector3.yAxis end if UIS:IsKeyDown(Enum.KeyCode.LeftShift) then move -= Vector3.yAxis end end if move.Magnitude > 0 then move = move.Unit end root.CFrame = root.CFrame + move * Config.FlySpeed * math.clamp(dt, 0, 0.1) root.AssemblyLinearVelocity = Vector3.zero end -- Unified movement controller (Heartbeat, after physics). Priority: -- circle strafe (drives its own fly) > standalone fly > nothing. Speed and -- super jump apply independently. One PlatformStand owner so nothing fights. connect(RunService.Heartbeat, function(dt) local char = player.Character local root = char and char:FindFirstChild("HumanoidRootPart") local humanoid = char and char:FindFirstChildOfClass("Humanoid") pcall(applyStatMods, humanoid) if not (active and not renderFailed and root and humanoid and humanoid.Health > 0) then if flying then stopFly(humanoid) end hideRing() return end local busyUI = UIS:GetFocusedTextBox() or GuiService.MenuIsOpen local target = (Config.CircleStrafe and toggles[KEYS.Strafe] and not busyUI) and nearestEnemy(root.Position, Config.CircleRange) or nil if target and target.root then local tpos = target.root.Position if not flying then platformStash = humanoid.PlatformStand; flying = true end humanoid.PlatformStand = true local desired if Config.CircleStrafeMode == "BehindBack" then desired = tpos - target.root.CFrame.LookVector * Config.CircleRadius + Vector3.new(0, Config.CircleHeight, 0) else orbitAngle = orbitAngle + Config.CircleSpeed * math.clamp(dt, 0, 0.1) desired = tpos + Vector3.new(math.cos(orbitAngle), 0, math.sin(orbitAngle)) * Config.CircleRadius + Vector3.new(0, Config.CircleHeight, 0) end local goal = CFrame.lookAt(desired, Vector3.new(tpos.X, desired.Y, tpos.Z)) root.CFrame = root.CFrame:Lerp(goal, math.clamp(Config.StrafeSmooth, 0.05, 1)) root.AssemblyLinearVelocity = Vector3.zero drawRing(Vector3.new(tpos.X, tpos.Y - 2.5, tpos.Z), Config.CircleRadius, Color3.fromRGB(120, 200, 255)) return end hideRing() if Config.Fly and not busyUI then manualFly(dt, root, humanoid) return elseif flying then stopFly(humanoid) end -- Speed: nudge the character along its real move input each frame. Survives -- the game re-setting WalkSpeed; adds on top of normal walking. if active and Config.Speed and not busyUI and humanoid.MoveDirection.Magnitude > 0.05 then root.CFrame = root.CFrame + humanoid.MoveDirection * Config.SpeedBoost * math.clamp(dt, 0, 0.1) end end) -- HUD refresh ---------------------------------------------------------------- connect(RunService.Heartbeat, function() hud.Visible = active and Config.ShowHud == true if not hud.Visible then return end local on, off = Color3.fromRGB(120, 230, 150), Color3.fromRGB(150, 160, 170) hudStrafe.Text = "[" .. KEYS.Strafe.Name .. "] Circle Strafe" hudStrafe.TextColor3 = toggles[KEYS.Strafe] and on or off hudMode.Text = "[" .. KEYS.Mode.Name .. "] Mode: " .. (Config.CircleStrafeMode == "BehindBack" and "Behind-Back" or "Orbit") hudMode.TextColor3 = Color3.fromRGB(200, 200, 210) hudSpread.Text = "No Spread" hudSpread.TextColor3 = Config.NoSpread and on or off local act = {} if toggles[KEYS.Strafe] then act[#act + 1] = "STRAFE" end if flying then act[#act + 1] = "FLY" end if Config.NoSpread then act[#act + 1] = "NOSPREAD" end hudActive.Text = #act > 0 and ("ACTIVE: " .. table.concat(act, " ")) or "idle" hudActive.TextColor3 = #act > 0 and Color3.fromRGB(255, 219, 103) or off end) table.insert(destructors, function() hideRing() local char = player.Character local humanoid = char and char:FindFirstChildOfClass("Humanoid") if flying and humanoid and platformStash ~= nil then humanoid.PlatformStand = platformStash end flying = false if humanoid and savedUseJP ~= nil then pcall(function() humanoid.UseJumpPower, humanoid.JumpPower, humanoid.JumpHeight = savedUseJP, savedJP, savedJH end) end if hud then hud:Destroy() end end) print("[Kingfisher] Loaded. Insert: menu. AIM and AUTO FIRE start OFF. SILENT covers all weapons. Toggle [End] Circle Strafe ([B] mode). Click X to unload.") return {Settings = Config, Unload = unload, RunMathTests = mathTests}