local ReplicatedStorage = game:GetService("ReplicatedStorage") local Players = game:GetService("Players") local TweenService = game:GetService("TweenService") local RunService = game:GetService("RunService") local LocalPlayer = Players.LocalPlayer local CONFIG = { FireDelay = 0.37, RetryDelay = 0.04, RetryFire = true, FacingDotThreshold = -0.6, LowHPThreshold = 15, ChainResetTime = 2, FaceCheckMaxDist = 8, BehindOffset = 5, DashSideRadius = 4.5, -- Dash humanizado: duração base por stud percorrido + jitter DashSpeedPerStud = 0.026, -- segundos por stud (ligeiramente mais lento = mais peso, mais intencional) DashMinDuration = 0.14, -- mínimo absoluto aumentado (elimina flash em alvo próximo) DashMaxDuration = 0.32, -- máximo levemente maior pra dar espaço pro Cubic InOut respirar DashTimeJitter = 0.04, -- ±0.04s variação aleatória de tempo por dash DashRadiusJitter = 1.2, -- ±1.2 stud no raio lateral (variação mais perceptível entre dashes) DashArcHeight = 0.3, -- offset Y no midpoint do arco (curvatura 3D sutil, não fica flat) FireDelayJitter = 0.015, -- pequena margem de tolerância pro golden delay não falhar com variação de ping -- Lock On câmera LockOnSmoothness = 0.12, -- 0 = instantâneo, 1 = nunca chega. 0.12 = suave mas responsivo LockOnHeightOffset = 2.0, -- mira um pouco acima do HRP (mais pro tronco/cabeça) } if _G.retryfire ~= nil then CONFIG.RetryFire = _G.retryfire end local function getRemote(...) local path = { ... } local ok, remote = pcall(function() local node = ReplicatedStorage for _, child in ipairs(path) do node = node:WaitForChild(child, 5) end return node end) return ok and remote or nil end local targetRemote = getRemote("Knit","Knit","Services","DivergentFistService","RE","Activated") if not targetRemote then warn("[DivergentFist] Remote not found!") return end local returnSkillRemote = getRemote("Knit","Knit","Services","ItadoriService","RE","RightActivated") local function getHRP() local char = LocalPlayer.Character return char and char:FindFirstChild("HumanoidRootPart") end local function isAliveModel(model) local myChar = LocalPlayer.Character if model == myChar then return false end local root = model:FindFirstChild("HumanoidRootPart") local humanoid = model:FindFirstChild("Humanoid") return root and humanoid and humanoid.Health > 0 end local function findNearestTarget() local hrp = getHRP() if not hrp then return nil end local nearest = nil local bestDist = math.huge local function checkModel(model) if not isAliveModel(model) then return end local root = model:FindFirstChild("HumanoidRootPart") local dist = (hrp.Position - root.Position).Magnitude if dist < bestDist then bestDist = dist nearest = model end end for _, player in ipairs(Players:GetPlayers()) do if player ~= LocalPlayer and player.Character then checkModel(player.Character) end end for _, obj in ipairs(workspace:GetDescendants()) do if obj:IsA("Model") then checkModel(obj) end end return nearest end -- checa se EU estou atrás do alvo (dot bem negativo = eu tô na direção -- oposta ao LookVector dele, ou seja, atrás das costas dele). -- é a única situação que deveria pular o dash de reposição. local function isBehindTarget(targetRoot) local hrp = getHRP() if not hrp or not targetRoot or not targetRoot.Parent then return false end local toPlayer = (hrp.Position - targetRoot.Position) if toPlayer.Magnitude < 0.01 then return false end local dot = targetRoot.CFrame.LookVector:Dot(toPlayer.Unit) return dot < CONFIG.FacingDotThreshold end local function isClose(targetRoot) local hrp = getHRP() if not hrp or not targetRoot or not targetRoot.Parent then return false end return (hrp.Position - targetRoot.Position).Magnitude <= CONFIG.FaceCheckMaxDist end local function isTargetInFrontClose(targetRoot) if not isClose(targetRoot) then return false end return not isBehindTarget(targetRoot) end local function getTargetHP(target) if not target then return math.huge end local humanoid = target:FindFirstChild("Humanoid") if not humanoid then return math.huge end return humanoid.Health end -- ────────────────────────────────────────────── -- LOCK ON – câmera olha suavemente pro alvo -- NÃO muda CameraType pra Scriptable (quebra input do BF!) -- Funciona via CFrame.lookAt + Lerp no RenderStepped -- Auto-desativa após 1 segundo -- ────────────────────────────────────────────── local camera = workspace.CurrentCamera local lockOnConn = nil -- conexão RenderStepped do lock on local lockOnTimer = nil -- task.delay de 1s pra desativar local function stopLockOn() if lockOnConn then lockOnConn:Disconnect() lockOnConn = nil end if lockOnTimer then task.cancel(lockOnTimer) lockOnTimer = nil end end local function startLockOn(targetRoot) -- Desconecta qualquer lock anterior stopLockOn() lockOnConn = RunService.RenderStepped:Connect(function() -- Para se o alvo sumiu ou morreu if not targetRoot or not targetRoot.Parent then stopLockOn() return end local hrp = getHRP() if not hrp then return end -- Ponto que a câmera vai olhar: HRP do alvo + offset de altura local aimPoint = targetRoot.Position + Vector3.new(0, CONFIG.LockOnHeightOffset, 0) -- CFrame atual da câmera (posição mantida, só muda a direção) local camPos = camera.CFrame.Position local wantedCF = CFrame.lookAt(camPos, aimPoint) -- Lerp suave: câmera gira em direção ao alvo sem travar o input camera.CFrame = camera.CFrame:Lerp(wantedCF, CONFIG.LockOnSmoothness) end) -- Auto-desativa após 1 segundo lockOnTimer = task.delay(1, function() stopLockOn() lockOnTimer = nil end) end -- ────────────────────────────────────────────── -- DASH 180: arco horizontal lateral, alterna L/R -- ────────────────────────────────────────────── local dashSide = "Left" local function dashBehindTarget(targetRoot) local hrp = getHRP() if not hrp or not targetRoot or not targetRoot.Parent then return end local side = dashSide dashSide = (side == "Left") and "Right" or "Left" local y = hrp.Position.Y local startPos = hrp.Position local rightVec = targetRoot.CFrame.RightVector local sideVec = (side == "Right") and rightVec or -rightVec -- raio lateral com jitter: evita arco perfeito e idêntico toda vez local radiusJitter = (math.random() * 2 - 1) * CONFIG.DashRadiusJitter local sideRadius = CONFIG.DashSideRadius + radiusJitter local midPos = targetRoot.Position + sideVec * sideRadius -- leve elevação no midpoint: arco tem curvatura 3D sutil ao invés de ser completamente flat midPos = Vector3.new(midPos.X, y + CONFIG.DashArcHeight, midPos.Z) -- duração proporcional à distância real a percorrer + jitter de tempo local lookDir = targetRoot.CFrame.LookVector local behindDest = targetRoot.Position - lookDir * CONFIG.BehindOffset behindDest = Vector3.new(behindDest.X, y, behindDest.Z) local totalDist = (startPos - midPos).Magnitude + (midPos - behindDest).Magnitude local baseDur = math.clamp(totalDist * CONFIG.DashSpeedPerStud, CONFIG.DashMinDuration, CONFIG.DashMaxDuration) local timeJitter = (math.random() * 2 - 1) * CONFIG.DashTimeJitter local duration = math.max(CONFIG.DashMinDuration, baseDur + timeJitter) local startTime = os.clock() while true do if not targetRoot.Parent then return end local alpha = (os.clock() - startTime) / duration if alpha >= 1 then break end -- Cubic InOut: arranca devagar, acelera no meio, desacelera no final -- parece movimento de corpo humano de verdade (wind-up → burst → brake) -- muito mais orgânico que Sine.Out que começa imediato demais local easedAlpha = TweenService:GetValue(alpha, Enum.EasingStyle.Cubic, Enum.EasingDirection.InOut) -- recalcula behindPos em tempo real (alvo pode se mover durante o dash) local curLookDir = targetRoot.CFrame.LookVector local behindPos = targetRoot.Position - curLookDir * CONFIG.BehindOffset behindPos = Vector3.new(behindPos.X, y, behindPos.Z) local p1 = startPos:Lerp(midPos, easedAlpha) local p2 = midPos:Lerp(behindPos, easedAlpha) local pos = p1:Lerp(p2, easedAlpha) hrp.CFrame = CFrame.new(pos, Vector3.new(targetRoot.Position.X, y, targetRoot.Position.Z)) RunService.Heartbeat:Wait() end if not targetRoot.Parent then return end local curLookDir = targetRoot.CFrame.LookVector local behindPos = targetRoot.Position - curLookDir * CONFIG.BehindOffset behindPos = Vector3.new(behindPos.X, y, behindPos.Z) hrp.CFrame = CFrame.new(behindPos, Vector3.new(targetRoot.Position.X, y, targetRoot.Position.Z)) print("[DivergentFist] Dash 180 → " .. side .. string.format(" (%.2fs, r=%.1f)", duration, sideRadius)) end -- ────────────────────────────────────────────── -- HOOK -- ────────────────────────────────────────────── local isCooling = false local isRetrying = false local chainCount = 0 local lastFireTime = 0 local lockedTarget = nil -- trava no alvo assim que a chain começa local oldNamecall oldNamecall = hookmetamethod(game, "__namecall", function(self, ...) if getnamecallmethod() ~= "FireServer" or self ~= targetRemote then return oldNamecall(self, ...) end if isRetrying then return oldNamecall(self, ...) end if isCooling then return oldNamecall(self, ...) end isCooling = true local now = tick() if (now - lastFireTime) > CONFIG.ChainResetTime then chainCount = 0 lockedTarget = nil -- chain nova: solta o lock antigo stopLockOn() -- reseta o lock on também quando a chain reinicia end lastFireTime = now chainCount = chainCount + 1 print(string.format("[DivergentFist] Black Flash #%d", chainCount)) local result = oldNamecall(self, ...) local args = { ... } -- lock: só busca alvo novo se ainda não tem lock ou se o lock morreu/sumiu if not lockedTarget or not lockedTarget.Parent or not isAliveModel(lockedTarget) then lockedTarget = findNearestTarget() end local target = lockedTarget local targetRoot = target and target:FindFirstChild("HumanoidRootPart") -- Lock On: reativa a cada disparo enquanto a chain estiver rolando, -- em vez de só quando o alvo muda. Isso mantém a câmera travada -- do começo ao fim da chain, não só nos primeiros 1s depois de travar. if targetRoot and targetRoot.Parent then startLockOn(targetRoot) end -- perto (qualquer ângulo: frente, lado, costas) → dash 180 pras costas if targetRoot and targetRoot.Parent and isClose(targetRoot) then task.spawn(function() dashBehindTarget(targetRoot) end) end task.delay(CONFIG.FireDelay, function() if chainCount == 4 then local hp = getTargetHP(target) if hp > CONFIG.LowHPThreshold then print(string.format("[DivergentFist] 4º BF – inimigo com %.0f HP > %d → cancelando", hp, CONFIG.LowHPThreshold)) if returnSkillRemote then pcall(function() returnSkillRemote:FireServer() end) end chainCount = 0 lockedTarget = nil stopLockOn() -- solta câmera quando cancela task.defer(function() isCooling = false end) return else print(string.format("[DivergentFist] 4º BF – inimigo com %.0f HP <= %d → deixa passar!", hp, CONFIG.LowHPThreshold)) end end if chainCount >= 4 then chainCount = 0 lockedTarget = nil stopLockOn() -- solta câmera quando chain completa end if targetRoot and targetRoot.Parent and not isBehindTarget(targetRoot) then -- ainda não tô nas costas dele: faz dash pras costas e continua a chain if isClose(targetRoot) then task.spawn(function() dashBehindTarget(targetRoot) end) end task.spawn(function() task.wait(CONFIG.RetryDelay) if not targetRoot.Parent or not isAliveModel(targetRoot.Parent) then stopLockOn() task.defer(function() isCooling = false end) return end local shouldRetryFire = (_G.retryfire ~= nil) and _G.retryfire or CONFIG.RetryFire local perto = isClose(targetRoot) local stillNotBehind = perto and not isBehindTarget(targetRoot) -- reposicionamento (dash) só acontece perto do alvo if stillNotBehind then print("[DivergentFist] Ainda nao tô atras - dash 180 de novo") dashBehindTarget(targetRoot) if targetRoot.Parent and isAliveModel(targetRoot.Parent) then stillNotBehind = not isBehindTarget(targetRoot) end end if stillNotBehind then print("[DivergentFist] Nao deu pra reposicionar - desistindo") elseif not shouldRetryFire then print("[DivergentFist] RetryFire OFF") elseif not isAliveModel(targetRoot.Parent) then -- alvo morreu durante o delay: não dispara fire perdido print("[DivergentFist] Alvo morreu - cancelando retry") stopLockOn() else -- dispara o Black Flash independente da distância (perto ou longe) isRetrying = true pcall(function() targetRemote:FireServer(table.unpack(args)) end) task.wait(CONFIG.FireDelay + CONFIG.FireDelayJitter) pcall(function() targetRemote:FireServer(table.unpack(args)) end) isRetrying = false end task.defer(function() isCooling = false end) end) else -- já confirmado atrás do alvo: deixa o BF sair direto, sem dash if targetRoot and targetRoot.Parent then pcall(function() targetRemote:FireServer(table.unpack(args)) end) end task.defer(function() isCooling = false end) end end) return result end) print("[DivergentFist] Pronto! | LowHP: " .. CONFIG.LowHPThreshold .. " | ChainReset: " .. CONFIG.ChainResetTime .. "s | LockOn: ON") -- ────────────────────────────────────────────── -- LOOP: apaga DisableChase e FlashChain do Info -- ────────────────────────────────────────────── task.spawn(function() while task.wait(0.1) do local char = LocalPlayer.Character if char then local info = char:FindFirstChild("Info") if info then local disableChase = info:FindFirstChild("DisableChase") if disableChase then pcall(function() disableChase:Destroy() end) end local flashChain = info:FindFirstChild("FlashChain") if flashChain then pcall(function() flashChain:Destroy() end) end end end end end)