
KeylessUniversal

local UIS = game:GetService("UserInputService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
local camera = Workspace.CurrentCamera
---------------------------------------------------
-- CONFIGS
---------------------------------------------------
local maxDistance = 5000
local pullStrength = 1 -- rope tension
local boostForce = 70 -- CTRL boost
local idlePull = 20 -- gentle pull toward anchor
local maxSwingSpeed = 200 -- maximum swing speed
local airDrag = 1 -- speed decay
local cableThickness = 0.45
local aimRadius = 25 -- radius for aim assist in studs
-- FOV boost settings
local defaultFOV = camera and camera.FieldOfView or 70
local fovMax = 95 -- maximum FOV at top speed
local fovSpeedStart = 60 -- speed (studs/s) where FOV starts increasing
local fovSpeedMax = 200 -- speed that yields full fovMax
local fovLerpSpeed = 6 -- smoothing factor (higher = faster)
-- Grapple distance multiplier settings
local grappleDistanceStart = 30 -- distance (studs) where extra pull begins
local grappleDistanceMax = maxDistance
local grappleMaxMultiplier = 2.0 -- max multiplier at farthest distance
local grappleMinMultiplier = 1.0 -- multiplier at or below start distance
---------------------------------------------------
local left = { active = false }
local right = { active = false }
local boosting = false
local function createAnchor(position, hitPart)
local anchor = Instance.new("Part")
anchor.Size = Vector3.new(0.4, 0.4, 0.4)
anchor.Anchored = true
anchor.CanCollide = false
anchor.Transparency = 1
anchor.Position = position
anchor.Parent = Workspace
if hitPart then
local weld = Instance.new("WeldConstraint")
weld.Part0 = anchor
weld.Part1 = hitPart
weld.Parent = anchor
end
return anchor
end
local function createCable(color)
local attach0 = Instance.new("Attachment")
attach0.Position = Vector3.new(0, 0.5, 0)
attach0.Parent = humanoidRootPart
local beam = Instance.new("Beam")
beam.Attachment0 = attach0
beam.Width0 = cableThickness
beam.Width1 = cableThickness
beam.FaceCamera = true
beam.LightEmission = 0.7
beam.Color = ColorSequence.new(color)
beam.Parent = humanoidRootPart
return beam, attach0
end
local function getMouseHit()
local mouse = player:GetMouse()
local ray = camera:ScreenPointToRay(mouse.X, mouse.Y)
local params = RaycastParams.new()
params.FilterDescendantsInstances = { character }
params.FilterType = Enum.RaycastFilterType.Blacklist
local result = Workspace:Raycast(ray.Origin, ray.Direction * maxDistance, params)
if result and result.Instance and result.Instance.CanCollide then
return result.Position, result.Instance
end
local closestPart
local closestPoint
local closestDist = math.huge
local rayEnd = ray.Origin + ray.Direction * maxDistance
for _, part in ipairs(Workspace:GetDescendants()) do
if part:IsA("BasePart") and part.CanCollide then
local point = part.Position
local dist = (point - rayEnd).Magnitude
if dist < aimRadius and dist < closestDist then
closestDist = dist
closestPart = part
closestPoint = point
end
end
end
if closestPart then
return closestPoint, closestPart
end
return nil, nil
end
local function fire(side)
local data = (side == "left") and left or right
if data.active then return end
local hitPos, hitPart = getMouseHit()
if not hitPos or not hitPart then return end
data.anchor = createAnchor(hitPos, hitPart)
data.attach1 = Instance.new("Attachment", data.anchor)
data.beam, data.attach0 = createCable(
side == "left" and Color3.fromRGB(255, 70, 70)
or Color3.fromRGB(80, 180, 255)
)
data.beam.Attachment1 = data.attach1
data.length = (humanoidRootPart.Position - hitPos).Magnitude
-- compute per-grapple pull multiplier based on distance
local dist = data.length
local t = 0
if dist > grappleDistanceStart then
t = math.clamp((dist - grappleDistanceStart) / math.max(1, (grappleDistanceMax - grappleDistanceStart)), 0, 1)
end
data.pullMultiplier = grappleMinMultiplier + (grappleMaxMultiplier - grappleMinMultiplier) * t
data.active = true
end
local function release(side)
local data = (side == "left") and left or right
if not data.active then return end
data.beam:Destroy()
data.attach0:Destroy()
data.attach1:Destroy()
data.anchor:Destroy()
data.active = false
end
RunService.Heartbeat:Connect(function(dt)
for _, data in ipairs({ left, right }) do
if data.active then
local hrp = humanoidRootPart
local toAnchor = data.anchor.Position - hrp.Position
local distance = toAnchor.Magnitude
local dir = toAnchor.Unit
if distance > data.length then
hrp:ApplyImpulse(dir * (distance - data.length) * pullStrength * (data.pullMultiplier or 1))
end
hrp:ApplyImpulse(dir * idlePull * (data.pullMultiplier or 1))
if boosting then
hrp:ApplyImpulse(dir * boostForce * (data.pullMultiplier or 1))
end
local vel = hrp.AssemblyLinearVelocity
if vel.Magnitude > maxSwingSpeed then
hrp.AssemblyLinearVelocity = vel.Unit * maxSwingSpeed
end
hrp.AssemblyLinearVelocity *= airDrag
end
end
-- FOV boost based on speed
local speed = 0
if humanoidRootPart and humanoidRootPart.AssemblyLinearVelocity then
speed = humanoidRootPart.AssemblyLinearVelocity.Magnitude
end
local t = 0
if speed > fovSpeedStart then
t = math.clamp((speed - fovSpeedStart) / math.max(1, (fovSpeedMax - fovSpeedStart)), 0, 1)
end
local targetFOV = defaultFOV + (fovMax - defaultFOV) * t
if camera then
camera.FieldOfView = camera.FieldOfView + (targetFOV - camera.FieldOfView) * math.clamp(fovLerpSpeed * dt, 0, 1)
end
end)
UIS.InputBegan:Connect(function(input, gp)
if gp then return end
if input.KeyCode == Enum.KeyCode.Q then
fire("left")
elseif input.KeyCode == Enum.KeyCode.E then
fire("right")
elseif input.KeyCode == Enum.KeyCode.LeftControl or input.KeyCode == Enum.KeyCode.RightControl then
boosting = true
end
end)
UIS.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.Q then
release("left")
elseif input.KeyCode == Enum.KeyCode.E then
release("right")
elseif input.KeyCode == Enum.KeyCode.LeftControl or input.KeyCode == Enum.KeyCode.RightControl then
boosting = false
end
end)
player.CharacterAdded:Connect(function(char)
character = char
humanoidRootPart = char:WaitForChild("HumanoidRootPart")
boosting = false
release("left")
release("right")
end)
---------------------------------------------------
print("ODM GRAPPLE LOADED")
print("Hold Q/E = Grapple | Hold CTRL = Boost | Aim near objects to auto-snap")



Can u make a mobile version?
@Urlocalhecker i made mobile version check my scripts