JIT
Enhanced SelfYeet Combat Bot Script
--made by epiccooldude and auzer (advanced version with enhanced SelfYeet) local runService = game:GetService("RunService") local userInputService = game:GetService("UserInputService") local camera = workspace.CurrentCamera local player = game.Players.LocalPlayer local enabled = false local c = {} local playerObjects = {} local punchTool, yeetTool, selfYeetTool local leftSwingAnimId = "rbxassetid://7218622714" local rightSwingAnimId = "rbxassetid://7218624486" local aggroOffsetMultiplier = 1.5 local defOffsetMultiplier = 10 local attackRange = 66 -- Set the attack range to 66 units local retreatDistance = 10 -- Distance used for dodging -- New variables: local minDistance = 30 -- Bot will not retreat if closer than 30 units local hitDelay = 0.6 -- Delay (in seconds) from attack animation start to hit local selfYeetCooldown = 3 -- Reduced cooldown for more frequent selfYeet usage local lastSelfYeetTime = 0 -- Tracks when we last used selfYeet local selfYeetMaxDistance = 500 -- Maximum distance to consider using selfYeet local selfYeetMidFightChance = 0.3 -- 30% chance to selfYeet mid-fight for repositioning -- Advanced field: how much earlier to lead our attack if enemy is moving fast. -- This value will be computed adaptively. local maxLeadTime = 0.3 local playerDataClass = { char = nil, humanoidRootPart = nil, humanoid = nil, bodyGyro = nil, alive = false, player = nil, attackDirection = "None", focusPart = nil, offsetMultiplier = aggroOffsetMultiplier, c = {}, -- Field to store when an attack animation started: lastAttackStartTime = nil, } local playerData local targetData local active = true local runtime = { states = {} } local function CopyTable(target, destination, references) references = references or {} local copy = destination and CopyTable(destination) or {} references[target] = copy for k, v in pairs(target) do if type(v) == "table" then copy[k] = references[v] or CopyTable(v, nil, references) else copy[k] = v end end return copy end function playerDataClass:GetPosition() return self.humanoidRootPart.Position end function playerDataClass:GetCFrame() return self.humanoidRootPart.CFrame end function playerDataClass:GetDistance(point) return (self:GetPosition() - point).Magnitude end -- Always face the enemy. function playerDataClass:LookAt(point, aimFocus) self.bodyGyro.CFrame = CFrame.new(aimFocus and self:GetFocusPoint() or self:GetPosition(), point) end function playerDataClass:new(player) self = CopyTable(self) self.player = player if player.Character then self:OnCharacterAdded(player.Character) end c[#c + 1] = player.CharacterAdded:Connect(function(char) self:OnCharacterAdded(char) end) playerObjects[player] = self return self end function playerDataClass:remove() for _, connection in ipairs(self.c) do connection:Disconnect() end if self.bodyGyro then self.bodyGyro:Destroy() end end function playerDataClass:OnToolAdded(instance) if not instance:IsA("Tool") then return end if instance.Name == "Yeet" then yeetTool = instance elseif instance.Name == "Punch" then punchTool = instance elseif instance.Name == "SelfYeet" then selfYeetTool = instance end end function playerDataClass:UpdateFocus(point) local bodyParts = {self.leftHand, self.rightHand, self.humanoidRootPart} local closestData = { distance = math.huge } for _, part in ipairs(bodyParts) do local distance = (point - part.Position).Magnitude if distance < closestData.distance then closestData.part = part closestData.distance = distance end end self.focusPart = closestData.part end function playerDataClass:UpdateAnimations() -- Check playing animations and record when an attack started. for _, instance in ipairs(self.animator:GetPlayingAnimationTracks()) do if instance.Animation.AnimationId == leftSwingAnimId or instance.Animation.AnimationId == rightSwingAnimId then self.attackDirection = (instance.Animation.AnimationId == leftSwingAnimId and "Left") or (instance.Animation.AnimationId == rightSwingAnimId and "Right") self.offsetMultiplier = defOffsetMultiplier self.lastAttackStartTime = tick() -- Record attack start time return end end self.attackDirection = "None" self.offsetMultiplier = aggroOffsetMultiplier end function playerDataClass:GetFocusPoint() return self.focusPart.Position end function playerDataClass:OnCharacterAdded(char) self.char = char self.humanoidRootPart = self.char:FindFirstChild("HumanoidRootPart") self.humanoid = self.char:FindFirstChild("Humanoid") self.animator = self.humanoid:WaitForChild("Animator") self.leftHand = self.char:WaitForChild("LeftHand") self.rightHand = self.char:WaitForChild("RightHand") self.focusPart = self.humanoidRootPart if self.player == game.Players.LocalPlayer then self.bodyGyro = Instance.new("BodyGyro") self.bodyGyro.P = 0 self.bodyGyro.D = 100 self.bodyGyro.MaxTorque = Vector3.new(0, 10000000, 0) self.bodyGyro.Parent = self.humanoidRootPart c[#c + 1] = char.ChildAdded:Connect(function(child) self:OnToolAdded(child) end) self:OnToolAdded(self.char:FindFirstChildOfClass("Tool") or workspace) c[#c + 1] = self.humanoid.Died:Connect(function() self.alive = false end) end self.alive = true end playerData = CopyTable(playerDataClass) local function errorHandler(err) warn(err .. "\n" .. debug.traceback()) end function runtime:DisableState(stateName) runtime.states[stateName].active = false while runtime.states[stateName].tasks ~= 0 do task.wait() end end function runtime:DisableStates() for stateName, state in pairs(runtime.states) do if stateName ~= "Default" and state.active then runtime:DisableState(stateName) end end end function runtime:EnableState(stateName) if runtime.states[stateName].active then return end local state = runtime.states[stateName] local dt = 0 state.tasks = 0 state.active = true for _, func in pairs(state.functions) do state.tasks = state.tasks + 1 task.spawn(function() while active and state.active do dt = runService.Heartbeat:Wait() xpcall(function() func(state, dt) end, errorHandler) end state.tasks = state.tasks - 1 end) end end function runtime:SwitchState(stateName) runtime:DisableStates() runtime:EnableState(stateName) end function runtime:NewState(stateName) local data = { functions = {}, tasks = 0, active = false } runtime.states[stateName] = data return data end runtime:NewState("Default") runtime:NewState("Attack") local function ScanPlayers() local closestPlayerData = { distance = math.huge } for _, targetPlayer in ipairs(game.Players:GetChildren()) do if targetPlayer == game.Players.LocalPlayer then continue end local targetChar = targetPlayer.Character if not targetChar then continue end local humanoidRootPart = targetChar:FindFirstChild("HumanoidRootPart") local humanoid = targetChar:FindFirstChild("Humanoid") if not humanoidRootPart or not humanoid or humanoid.Health == 0 or humanoidRootPart.AssemblyMass < playerData.humanoidRootPart.AssemblyMass - 70000 then continue end local distance = playerData:GetDistance(humanoidRootPart.Position) if distance < closestPlayerData.distance then closestPlayerData = { distance = distance, player = targetPlayer } end end if closestPlayerData.player then targetData = playerObjects[closestPlayerData.player] targetData:UpdateAnimations() targetData:UpdateFocus(playerData.focusPart.Position) playerData:UpdateFocus(targetData.humanoidRootPart.Position) else if targetData then targetData:remove() end targetData = nil end task.wait(0.1) end -- Enhanced SelfYeet function with multiple tactical positions local function UseSelfYeet(positionType) if not selfYeetTool or not selfYeetTool.Parent or not targetData then return false end local currentTime = tick() if currentTime - lastSelfYeetTime < selfYeetCooldown then return false end local targetPosition = targetData:GetPosition() local targetCFrame = targetData:GetCFrame() local selfYeetPosition -- Different tactical positions based on the requested type if positionType == "behind" then -- Position behind the target selfYeetPosition = targetPosition - (targetCFrame.LookVector * 6) elseif positionType == "side" then -- Position to the side of the target (randomly left or right) local sideDir = math.random() > 0.5 and targetCFrame.RightVector or -targetCFrame.RightVector selfYeetPosition = targetPosition + (sideDir * 5) elseif positionType == "front" then -- Position in front of the target selfYeetPosition = targetPosition + (targetCFrame.LookVector * 6) elseif positionType == "above" then -- Position slightly above the target selfYeetPosition = targetPosition + Vector3.new(0, 7, 0) elseif positionType == "long_distance" then -- For long distances, aim directly at the target position selfYeetPosition = targetPosition else -- Default to a random tactical position local positions = {"behind", "side", "front"} return UseSelfYeet(positions[math.random(1, #positions)]) end -- Aim camera at the desired selfYeet position (critical, as camera direction determines selfYeet direction) camera.CFrame = CFrame.new(camera.CFrame.Position, selfYeetPosition) -- Equip and activate SelfYeet if selfYeetTool.Parent == player.Backpack then playerData.humanoid:EquipTool(selfYeetTool) task.wait(0.1) -- Small delay for equip end selfYeetTool:Activate() lastSelfYeetTime = currentTime -- Schedule recovery from ragdoll after selfYeet task.delay(0.5, function() -- Recovery code to get up after selfYeet game:GetService("Players").LocalPlayer.PlayerGui.RTGui.codebase.ragdoll.Events.Toggle:FireServer(table.unpack({ [1] = "R", [2] = false, })) end) return true end local function TrackCharacters() if not targetData or not targetData.alive then if playerData.bodyGyro then playerData.bodyGyro.P = 0 end return end playerData.bodyGyro.P = 1000000 local playerPos = playerData:GetFocusPoint() local targetPos = targetData:GetFocusPoint() local distanceToTarget = (targetPos - playerPos).Magnitude -- Force facing: always look at enemy's position. playerData:LookAt(targetPos, true) -- Long distance SelfYeet (500 studs or farther) if distanceToTarget >= selfYeetMaxDistance and UseSelfYeet("long_distance") then return end local currentTime = tick() local xz = Vector3.new(1, 0, 1) -- Mid-fight random SelfYeet for repositioning if distanceToTarget < attackRange * 1.5 and distanceToTarget > minDistance and math.random() < selfYeetMidFightChance and currentTime - lastSelfYeetTime > selfYeetCooldown then -- Randomly choose a tactical position (side, behind, or front) local positions = {"side", "behind", "front"} -- If enemy is attacking, prioritize getting behind or to the side if targetData.attackDirection ~= "None" then positions = {"behind", "side"} end if UseSelfYeet(positions[math.random(1, #positions)]) then return end end -- Advanced dodge: if enemy is attacking (pre-hit phase) and moving fast, dodge more aggressively. if targetData.lastAttackStartTime and (currentTime - targetData.lastAttackStartTime) < hitDelay then -- If we're being attacked, consider using SelfYeet to dodge (30% chance) if math.random() < 0.3 then if UseSelfYeet("side") then return end end -- Standard dodge if SelfYeet not used local dodgeDir if targetData.attackDirection == "Left" then dodgeDir = targetData:GetCFrame().rightVector elseif targetData.attackDirection == "Right" then dodgeDir = -targetData:GetCFrame().rightVector else dodgeDir = playerData:GetCFrame().rightVector end playerData.humanoid:MoveTo(playerPos + dodgeDir * retreatDistance) return end local lookVector = (targetPos - (targetData:GetCFrame() * CFrame.new(1, 0, 0)).p).unit local vector = (targetPos - playerPos) * xz local lookDirection = targetData:GetCFrame().lookVector local movementAngle = math.acos(vector:Dot(lookDirection) / vector.magnitude) local targetAngle = math.asin(vector:Dot(lookVector) / vector.magnitude) local rotDirection = 0 if math.deg(movementAngle) >= 1 then rotDirection = -math.sign(targetAngle) * math.max(1, vector.magnitude / 3) end local aggroOffset = playerData.humanoidRootPart.Size.X / 2 + targetData.humanoidRootPart.Size.X / 2 local defOffset = aggroOffset * targetData.offsetMultiplier local myLookDirection = playerData:GetCFrame().lookVector local offset = defOffset + (aggroOffset - defOffset) * (myLookDirection:Dot(lookVector) + 1) / 2 local movePoint = (CFrame.new(playerPos * xz, targetPos * xz) * CFrame.new(rotDirection, 0, offset - vector.magnitude)).Position -- Normal movement logic if distanceToTarget > attackRange * 1.5 and math.random() < 0.4 then -- Occasionally use SelfYeet to close distance quickly UseSelfYeet("front") elseif distanceToTarget > attackRange then playerData.humanoid:MoveTo(movePoint) elseif distanceToTarget < minDistance then local rightVector = playerData.humanoidRootPart.CFrame.rightVector local lateralDir = (targetPos - playerPos).Unit local dot = lateralDir:Dot(rightVector) local dodgeDirection = (dot >= 0 and rightVector or -rightVector) playerData.humanoid:MoveTo(playerPos + dodgeDirection * retreatDistance) elseif distanceToTarget < attackRange then playerData.humanoid:MoveTo(playerPos - myLookDirection * retreatDistance) else playerData.humanoid:MoveTo(movePoint) end end -- SUPER OP Attack function with advanced prediction. local function Attack() local currentTime = tick() local ourPredictedHitTime = currentTime + hitDelay -- Get enemy's velocity (if available). local enemyVel = (targetData and targetData.humanoidRootPart.AssemblyLinearVelocity) or Vector3.new(0, 0, 0) -- Predict enemy's hit time. local enemyAttackStart = targetData and targetData.lastAttackStartTime or currentTime local enemyPredictedHitTime = enemyAttackStart + hitDelay -- Predict enemy's position at hit time. local enemyPredictedPos = targetData and (targetData.humanoidRootPart.Position + enemyVel * hitDelay) or targetData:GetFocusPoint() -- Calculate adaptive lead time based on enemy speed. local enemySpeed = enemyVel.Magnitude local leadTime = math.clamp(enemySpeed * 0.005, 0, maxLeadTime) -- Our effective hit time is adjusted by leadTime (attacking earlier). local ourEffectiveHitTime = ourPredictedHitTime - leadTime -- Use math to decide: if our effective hit lands before enemy's, attack now. if ourEffectiveHitTime <= enemyPredictedHitTime then UseTool(punchTool) if yeetTool then task.wait(0.5) end UseTool(yeetTool) playerData.lastAttackStartTime = currentTime else -- Otherwise, schedule our attack so that it lands just before enemy's. local delayTime = (enemyPredictedHitTime - ourEffectiveHitTime) - 0.05 if delayTime < 0 then delayTime = 0 end task.delay(delayTime, function() if active and targetData and targetData.alive then UseTool(punchTool) if yeetTool then task.wait(0.5) end UseTool(yeetTool) playerData.lastAttackStartTime = tick() end end) end end -- Function to automatically equip and use tools function UseTool(tool) if not tool or not tool.Parent then return end if tool.Parent == player.Backpack then playerData.humanoid:EquipTool(tool) end tool:Activate() end -- Function to ensure tools are equipped local function EnsureToolsEquipped() local backpack = player:WaitForChild("Backpack") -- Check for and equip all relevant tools if not already equipped if not yeetTool then local yeetInBackpack = backpack:FindFirstChild("Yeet") if yeetInBackpack then yeetTool = yeetInBackpack end end if not punchTool then local punchInBackpack = backpack:FindFirstChild("Punch") if punchInBackpack then punchTool = punchInBackpack end end if not selfYeetTool then local selfYeetInBackpack = backpack:FindFirstChild("SelfYeet") if selfYeetInBackpack then selfYeetTool = selfYeetInBackpack end end task.wait(1) -- Check periodically end local function onToolAdded(instance) if not instance:IsA("Tool") then return end if instance.Name == "Yeet" then yeetTool = instance elseif instance.Name == "Punch" then punchTool = instance elseif instance.Name == "SelfYeet" then selfYeetTool = instance end end c[#c + 1] = userInputService.InputBegan:Connect(function(input) if input.KeyCode == Enum.KeyCode.End then for _, connection in ipairs(c) do connection:Disconnect() end active = false runtime:DisableStates() playerData:remove() elseif input.KeyCode == Enum.KeyCode.X then if enabled then enabled = false runtime:DisableState("Attack") else enabled = true runtime:EnableState("Attack") end end end) playerData = playerDataClass:new(player) for _, p in ipairs(game.Players:GetChildren()) do if p == game.Players.LocalPlayer then continue end playerDataClass:new(p) end c[#c + 1] = game.Players.PlayerAdded:Connect(function(p) playerDataClass:new(p) end) runtime.states.Default.functions[ScanPlayers] = ScanPlayers runtime.states.Default.functions[EnsureToolsEquipped] = EnsureToolsEquipped runtime.states.Attack.functions[TrackCharacters] = TrackCharacters runtime.states.Attack.functions[Attack] = Attack runtime:EnableState("Default") print("Enhanced Combat Bot with Advanced SelfYeet loaded! Press X to toggle.") sometimes when selfyeeting, it doesnt have time to selfyeet, before it switches to the other tools, fix that

Okay, I'll adjust the script to ensure the SelfYeet action has enough time to execute before potentially switching to other tools.

I'll add a small delay after initiating SelfYeet and prevent other actions during this brief period.

Key Changes:

  1. isSelfYeeting Flag: Introduced a global flag isSelfYeeting to track when the SelfYeet action is in progress.
  2. UseSelfYeet Modifications:
    • Sets isSelfYeeting = true when initiated.
    • Increased the task.wait() after EquipTool to 0.2 seconds to allow more time for the equip animation.
    • Schedules isSelfYeeting = false after selfYeetDuration (set to 0.7 seconds, adjust if needed).
    • Returns true on successful initiation, false otherwise.
    • Added checks to prevent starting if already self-yeeting or if the tool/target is invalid.
  3. TrackCharacters Modifications:
    • Added if isSelfYeeting then return end at the beginning to prevent movement/dodging during SelfYeet.
    • Added return immediately after a successful UseSelfYeet call to prevent subsequent logic in the same frame.
  4. Attack Modifications:
    • Added if isSelfYeeting then return end at the beginning to prevent attacking during SelfYeet.
    • Added checks for isSelfYeeting before attempting the follow-up UseTool(yeetTool) in both immediate and delayed attacks.
  5. Tool Handling: Added checks in UseTool to verify the tool is actually equipped before activating. Added EnsureToolsAvailable to periodically check backpack/character for tools.
  6. Error Handling & Stability: Added more checks for playerData.alive, valid humanoids/parts, and target validity throughout the script to prevent errors, especially during respawns or when targets die/leave. Added basic error handling in the state runner (runtime:EnableState) to prevent script crashes. Added cleanup on PlayerRemoving and when disabling with the End key.

This should make the SelfYeet action more reliable and prevent other actions from interrupting it prematurely.*

Updated files
v1