-- ===================================== -- SERVICES -- ===================================== local Players = game:GetService("Players") local RunService = game:GetService("RunService") local Debris = game:GetService("Debris") local player = Players.LocalPlayer local mouse = player:GetMouse() local camera = workspace.CurrentCamera -- ===================================== -- SETTINGS -- ===================================== local BASE_OFFSET = Vector3.new(3, 3, 0) local SIZE_MULTIPLIER = 0.75 local THROW_FORCE = 350 -- powerful throw -- Extended network simulation local NETWORK_RADIUS = 300 -- max effective distance local SCAN_INTERVAL = 0.15 -- seconds -- ===================================== -- STATE -- ===================================== local grabbedPart = nil local alignPos, alignOri local currentOffset = Vector3.zero local scanTimer = 0 -- ===================================== -- NETWORK OWNERSHIP (SAFE) -- ===================================== local function claimOwnership(part) if part and part:IsA("BasePart") and not part.Anchored then pcall(function() sethiddenproperty(part, "NetworkOwnershipRule", Enum.NetworkOwnershipRule.Manual) part:SetNetworkOwner(player) end) end end RunService.Heartbeat:Connect(function(dt) scanTimer += dt if scanTimer < SCAN_INTERVAL then return end scanTimer = 0 if not player.Character then return end local hrp = player.Character:FindFirstChild("HumanoidRootPart") if not hrp then return end for _, part in ipairs(workspace:GetDescendants()) do if part:IsA("BasePart") and not part.Anchored and part ~= grabbedPart and (part.Position - hrp.Position).Magnitude <= NETWORK_RADIUS then claimOwnership(part) end end if grabbedPart then claimOwnership(grabbedPart) end end) -- ===================================== -- RELEASE FUNCTION -- ===================================== local function release() if grabbedPart then if alignPos then alignPos:Destroy() end if alignOri then alignOri:Destroy() end alignPos, alignOri = nil, nil grabbedPart = nil end end -- ===================================== -- CLICK TO GRAB -- ===================================== mouse.Button1Down:Connect(function() local target = mouse.Target if not target or not target:IsA("BasePart") or target.Anchored then return end if grabbedPart == target then release() return end release() grabbedPart = target claimOwnership(target) -- Size-based offset local size = target.Size local largestAxis = math.max(size.X, size.Y, size.Z) currentOffset = Vector3.new( BASE_OFFSET.X + largestAxis * SIZE_MULTIPLIER, BASE_OFFSET.Y + largestAxis * SIZE_MULTIPLIER, 0 ) -- AlignPosition alignPos = Instance.new("AlignPosition") alignPos.MaxForce = 1e6 alignPos.Responsiveness = 200 alignPos.Mode = Enum.PositionAlignmentMode.OneAttachment alignPos.Parent = target local att0 = Instance.new("Attachment") att0.Parent = target alignPos.Attachment0 = att0 -- AlignOrientation alignOri = Instance.new("AlignOrientation") alignOri.MaxTorque = 1e6 alignOri.Responsiveness = 200 alignOri.Mode = Enum.OrientationAlignmentMode.OneAttachment alignOri.Parent = target local att1 = Instance.new("Attachment") att1.Parent = target alignOri.Attachment0 = att1 end) -- ===================================== -- FOLLOW PLAYER -- ===================================== RunService.RenderStepped:Connect(function() if grabbedPart and alignPos and player.Character then local hrp = player.Character:FindFirstChild("HumanoidRootPart") if hrp then alignPos.Position = hrp.Position + hrp.CFrame.RightVector * currentOffset.X + Vector3.new(0, currentOffset.Y, 0) end end end) -- ===================================== -- THROW GUI (FUI) -- ===================================== local gui = Instance.new("ScreenGui") gui.Name = "ThrowGui" gui.ResetOnSpawn = false gui.Parent = player:WaitForChild("PlayerGui") local throwButton = Instance.new("TextButton") throwButton.Size = UDim2.fromScale(0.2, 0.09) throwButton.Position = UDim2.fromScale(0.78, 0.55) throwButton.Text = "THROW" throwButton.TextScaled = true throwButton.BackgroundColor3 = Color3.fromRGB(200, 60, 60) throwButton.TextColor3 = Color3.new(1,1,1) throwButton.Parent = gui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0.3, 0) corner.Parent = throwButton -- ===================================== -- TARGET DETECTION -- ===================================== local function getTargetPosition() local origin = camera.CFrame.Position local direction = camera.CFrame.LookVector * 600 local params = RaycastParams.new() params.FilterDescendantsInstances = {player.Character} params.FilterType = Enum.RaycastFilterType.Blacklist local result = workspace:Raycast(origin, direction, params) if result then local model = result.Instance:FindFirstAncestorOfClass("Model") if model and model:FindFirstChild("HumanoidRootPart") then return model.HumanoidRootPart.Position end end return origin + direction end -- ===================================== -- THROW ACTION (CENTERED, STRONG) -- ===================================== throwButton.MouseButton1Click:Connect(function() if not grabbedPart then return end local targetPos = getTargetPosition() local partCenter = grabbedPart.Position local direction = (targetPos - partCenter) if direction.Magnitude == 0 then return end direction = direction.Unit -- Remove constraints if alignPos then alignPos:Destroy() end if alignOri then alignOri:Destroy() end alignPos, alignOri = nil, nil -- Reset velocity for stable throw grabbedPart.AssemblyLinearVelocity = Vector3.zero grabbedPart.AssemblyAngularVelocity = Vector3.zero -- Apply velocity from center local bv = Instance.new("BodyVelocity") bv.MaxForce = Vector3.new(1e6, 1e6, 1e6) bv.P = 1e4 bv.Velocity = direction * THROW_FORCE bv.Parent = grabbedPart Debris:AddItem(bv, 0.35) grabbedPart = nil end)