--[[ TELEKINESIS V4.4 PC + MOBILE UNIFICADO CAMBIOS DE ESTA VERSIÓN - Ctrl derecho = mostrar / ocultar interfaz en PC - Supr deja de controlar la interfaz - Ocultar interfaz NO desactiva el sistema - Móvil puede ocultar / mostrar correctamente - Botón de mostrar móvil arriba a la izquierda - Highlights se restauran al mostrar - Imán: - controles arriba - Desactivar abajo izquierda - Anclar todo abajo derecha - Rotación: - flechas abajo izquierda - no ocupan el centro - Cursor visual conservado - Motor PC / móvil unificado ]] -------------------------------------------------- -- SERVICIOS -------------------------------------------------- local Players = game:GetService("Players") local UserInputService = game:GetService("UserInputService") local RunService = game:GetService("RunService") local StarterGui = game:GetService("StarterGui") local Debris = game:GetService("Debris") local CoreGui = game:GetService("CoreGui") local player = Players.LocalPlayer local mouse = player:GetMouse() local camera = workspace.CurrentCamera local isMobile = UserInputService.TouchEnabled -------------------------------------------------- -- CONFIG -------------------------------------------------- local CONFIG = { -- Lanzamiento throwForce = 1000, throwForceMin = 100, throwForceMax = 4000, throwForceStepPC = 100, throwForceStepMobile = 200, -- Imán magnetRadius = 30, magnetRadiusMin = 5, magnetRadiusMax = 200, magnetForce = 200, magnetForceMin = 50, magnetForceMax = 2000, magnetForceStep = 25, magnetRadiusStep = 2, -- Agarre holdDistanceDefault = 10, holdDistanceMin = 2, holdDistanceMax = 1000, distanceSpeed = 0.8, distanceKeySpeed = 0.4, -- Rotación rotationSpeed = 2, -- Física holdVelocityP = 12500, holdGyroP = 3000, -- Bloqueo de posición rotationPositionP = 20000, rotationPositionD = 1250, -- Cursor móvil pointerDragThreshold = 10, } -------------------------------------------------- -- ESTADO -------------------------------------------------- local STATE = { active = true, -- IMPORTANTE: -- guiVisible controla solo la interfaz. guiVisible = true, holding = false, target = nil, holdDistance = CONFIG.holdDistanceDefault, anchoredWhileHolding = false, magnetActive = false, magnetObjects = {}, rotationMode = false, rotationKeys = { up = false, down = false, left = false, right = false, }, holdQ = false, holdE = false, holdClose = false, holdFar = false, rotationPosition = nil, -- Personaje characterVisibilityBackup = {}, characterFrozen = false, characterBackup = nil, -- Cursor móvil pointerTouch = nil, pointerTouchStart = nil, pointerDragStarted = false, -- Modo móvil mobileMode = "normal", -- Notificaciones lastNotificationTime = 0, notificationCooldown = 0.25, } -------------------------------------------------- -- PERSONAJE -------------------------------------------------- local function getCharacter() return player.Character end local function getHumanoid() local character = getCharacter() return character and character:FindFirstChildOfClass("Humanoid") end local function getRootPart() local character = getCharacter() return character and character:FindFirstChild("HumanoidRootPart") end -------------------------------------------------- -- FÍSICA -------------------------------------------------- local bodyVelocity = Instance.new("BodyVelocity") bodyVelocity.Name = "TelekinesisVelocity" bodyVelocity.MaxForce = Vector3.new(1, 1, 1) * 1e5 bodyVelocity.P = CONFIG.holdVelocityP bodyVelocity.Velocity = Vector3.zero local bodyGyro = Instance.new("BodyGyro") bodyGyro.Name = "TelekinesisGyro" bodyGyro.MaxTorque = Vector3.new(1, 1, 1) * 1e6 bodyGyro.P = CONFIG.holdGyroP local rotationPositionLock = Instance.new("BodyPosition") rotationPositionLock.Name = "TelekinesisRotationPosition" rotationPositionLock.MaxForce = Vector3.new(1, 1, 1) * 1e7 rotationPositionLock.P = CONFIG.rotationPositionP rotationPositionLock.D = CONFIG.rotationPositionD rotationPositionLock.Position = Vector3.zero -------------------------------------------------- -- HIGHLIGHTS -------------------------------------------------- local highlightHolding = Instance.new("Highlight") highlightHolding.Name = "TelekinesisHolding" highlightHolding.FillColor = Color3.fromRGB(0, 255, 0) highlightHolding.OutlineColor = Color3.fromRGB(0, 255, 0) highlightHolding.FillTransparency = 0.5 highlightHolding.OutlineTransparency = 0 highlightHolding.DepthMode = Enum.HighlightDepthMode.Occluded highlightHolding.Enabled = true highlightHolding.Parent = CoreGui local highlightLooking = Instance.new("Highlight") highlightLooking.Name = "TelekinesisLooking" highlightLooking.FillColor = Color3.fromRGB(0, 170, 255) highlightLooking.OutlineColor = Color3.fromRGB(0, 170, 255) highlightLooking.FillTransparency = 0.6 highlightLooking.OutlineTransparency = 0 highlightLooking.DepthMode = Enum.HighlightDepthMode.Occluded highlightLooking.Enabled = true highlightLooking.Parent = CoreGui -------------------------------------------------- -- VISUAL IMÁN -------------------------------------------------- local usingDrawing = Drawing and Drawing.new and typeof(Drawing.new) == "function" local magnetCircle local circleGui local circleImage local surfacePosition = Vector3.zero local actualMagnetRadius = CONFIG.magnetRadius if usingDrawing then magnetCircle = Drawing.new("Circle") magnetCircle.Visible = false magnetCircle.Transparency = 1 magnetCircle.Color = Color3.fromRGB(0, 170, 255) magnetCircle.Thickness = 2 magnetCircle.Filled = false else circleGui = Instance.new("BillboardGui") circleGui.Name = "TelekinesisMagnetCircle" circleGui.Size = UDim2.fromOffset(100, 100) circleGui.AlwaysOnTop = true circleGui.Enabled = false circleGui.Parent = CoreGui circleImage = Instance.new("ImageLabel") circleImage.BackgroundTransparency = 1 circleImage.Image = "rbxassetid://13523341990" circleImage.ImageColor3 = Color3.fromRGB(0, 170, 255) circleImage.AnchorPoint = Vector2.new(0.5, 0.5) circleImage.Position = UDim2.fromScale(0.5, 0.5) circleImage.Size = UDim2.fromScale(1, 1) circleImage.Parent = circleGui end -------------------------------------------------- -- UI -------------------------------------------------- local UI = {} -------------------------------------------------- -- UI HELPERS -------------------------------------------------- local function makeCorner(object, radius) local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, radius or 12) corner.Parent = object return corner end local function makeStroke(object, transparency) local stroke = Instance.new("UIStroke") stroke.Color = Color3.fromRGB(255, 255, 255) stroke.Transparency = transparency or 0.75 stroke.Thickness = 1 stroke.Parent = object return stroke end local function styleButton(button) button.AutoButtonColor = false makeCorner(button, 14) makeStroke(button, 0.78) return button end -------------------------------------------------- -- GUI PC -------------------------------------------------- local function createMainGUI() local gui = Instance.new("ScreenGui") gui.Name = "TelekinesisUI" gui.ResetOnSpawn = false gui.IgnoreGuiInset = true gui.Parent = CoreGui UI.mainGui = gui local forceLabel = Instance.new("TextLabel") forceLabel.Name = "ForceLabel" forceLabel.BackgroundTransparency = 0.3 forceLabel.BackgroundColor3 = Color3.fromRGB(25, 25, 25) forceLabel.Size = UDim2.fromOffset(220, 60) forceLabel.Position = UDim2.new(1, -230, 1, -70) forceLabel.TextScaled = true forceLabel.Font = Enum.Font.GothamBold forceLabel.TextColor3 = Color3.new(1, 1, 1) forceLabel.TextStrokeTransparency = 0.5 forceLabel.Visible = not isMobile makeCorner(forceLabel, 14) makeStroke(forceLabel, 0.8) forceLabel.Parent = gui UI.forceLabel = forceLabel local rotationLabel = Instance.new("TextLabel") rotationLabel.Name = "RotationLabel" rotationLabel.BackgroundTransparency = 0.3 rotationLabel.BackgroundColor3 = Color3.fromRGB(25, 25, 25) rotationLabel.Size = UDim2.fromOffset(260, 70) rotationLabel.Position = UDim2.new(1, -270, 1, -80) rotationLabel.TextScaled = true rotationLabel.Font = Enum.Font.GothamBold rotationLabel.TextColor3 = Color3.new(1, 1, 1) rotationLabel.Text = "🔄 ROTACIÓN\nWASD / ↑↓←→" rotationLabel.Visible = false makeCorner(rotationLabel, 14) makeStroke(rotationLabel, 0.8) rotationLabel.Parent = gui UI.rotationLabel = rotationLabel end -------------------------------------------------- -- UI MÓVIL -------------------------------------------------- local function createMobileUI() local gui = Instance.new("ScreenGui") gui.Name = "TelekinesisMobile" gui.ResetOnSpawn = false gui.IgnoreGuiInset = true gui.Parent = CoreGui UI.mobileGui = gui -------------------------------------------------- -- CURSOR VISUAL -------------------------------------------------- local fakePointer = Instance.new("Frame") fakePointer.Name = "FakePointer" fakePointer.Size = UDim2.fromOffset(35, 35) fakePointer.Position = UDim2.new(0.5, 0, 0.4, 0) fakePointer.AnchorPoint = Vector2.new(0.5, 0.5) fakePointer.BackgroundColor3 = Color3.fromRGB(0, 170, 255) fakePointer.BackgroundTransparency = 0.4 fakePointer.Active = true fakePointer.ZIndex = 50 fakePointer.Parent = gui makeCorner(fakePointer, 35) makeStroke(fakePointer, 0.25) UI.fakePointer = fakePointer -------------------------------------------------- -- CONTENEDOR -------------------------------------------------- local container = Instance.new("Frame") container.Name = "Controls" container.Size = UDim2.fromScale(1, 1) container.BackgroundTransparency = 1 container.Parent = gui UI.mobileContainer = container -------------------------------------------------- -- CABECERA -------------------------------------------------- local header = Instance.new("Frame") header.Name = "Header" header.Size = UDim2.new(0, 230, 0, 55) header.Position = UDim2.new(0.5, -115, 0, 12) header.BackgroundColor3 = Color3.fromRGB(25, 25, 25) header.BackgroundTransparency = 0.18 header.ZIndex = 10 header.Parent = container makeCorner(header, 16) makeStroke(header, 0.7) UI.header = header -------------------------------------------------- -- MODO -------------------------------------------------- local modeLabel = Instance.new("TextLabel") modeLabel.Name = "ModeLabel" modeLabel.BackgroundTransparency = 1 modeLabel.Size = UDim2.new(1, -55, 1, 0) modeLabel.Position = UDim2.fromOffset(8, 0) modeLabel.Font = Enum.Font.GothamBold modeLabel.TextScaled = true modeLabel.TextColor3 = Color3.new(1, 1, 1) modeLabel.Text = "🎯 NORMAL" modeLabel.ZIndex = 11 modeLabel.Parent = header UI.modeLabel = modeLabel -------------------------------------------------- -- OJO -------------------------------------------------- local hideButton = Instance.new("TextButton") hideButton.Name = "Hide" hideButton.Size = UDim2.fromOffset(45, 45) hideButton.Position = UDim2.new(1, -50, 0, 5) hideButton.BackgroundColor3 = Color3.fromRGB(70, 70, 70) hideButton.BackgroundTransparency = 0.15 hideButton.Text = "👁️" hideButton.TextScaled = true hideButton.TextColor3 = Color3.new(1, 1, 1) hideButton.ZIndex = 12 styleButton(hideButton) hideButton.Parent = header UI.hideButton = hideButton -------------------------------------------------- -- PANEL -------------------------------------------------- local panel = Instance.new("Frame") panel.Name = "ModePanel" panel.Size = UDim2.new(1, 0, 0, 300) panel.Position = UDim2.new(0, 0, 1, -305) panel.BackgroundTransparency = 1 panel.ZIndex = 5 panel.Parent = container UI.panel = panel -------------------------------------------------- -- BOTÓN CENTRAL -------------------------------------------------- local actionButton = Instance.new("TextButton") actionButton.Name = "Action" actionButton.Size = UDim2.fromOffset(190, 68) actionButton.Position = UDim2.new(0.5, -95, 1, -80) actionButton.BackgroundColor3 = Color3.fromRGB(0, 190, 100) actionButton.BackgroundTransparency = 0.05 actionButton.Text = "✋ AGARRAR" actionButton.TextScaled = true actionButton.Font = Enum.Font.GothamBold actionButton.TextColor3 = Color3.new(1, 1, 1) actionButton.ZIndex = 10 styleButton(actionButton) actionButton.Parent = panel UI.actionButton = actionButton -------------------------------------------------- -- CREAR BOTÓN -------------------------------------------------- local function makeSmallButton( name, position, size, text, color ) local button = Instance.new("TextButton") button.Name = name button.Size = size button.Position = position button.BackgroundColor3 = color button.BackgroundTransparency = 0.15 button.Text = text button.TextScaled = true button.Font = Enum.Font.GothamBold button.TextColor3 = Color3.new(1, 1, 1) button.ZIndex = 10 styleButton(button) button.Parent = panel return button end -------------------------------------------------- -- NORMAL -------------------------------------------------- UI.buttons = {} UI.buttons.distanceDown = makeSmallButton( "DistanceDown", UDim2.new(0, 12, 1, -155), UDim2.fromOffset(72, 55), "📏\n−", Color3.fromRGB(60, 135, 200) ) UI.buttons.distanceUp = makeSmallButton( "DistanceUp", UDim2.new(0, 92, 1, -155), UDim2.fromOffset(72, 55), "📏\n+", Color3.fromRGB(60, 135, 200) ) UI.buttons.throw = makeSmallButton( "Throw", UDim2.new(1, -92, 1, -155), UDim2.fromOffset(80, 58), "🔥\nLANZAR", Color3.fromRGB(210, 70, 65) ) UI.buttons.anchor = makeSmallButton( "Anchor", UDim2.new(1, -178, 1, -155), UDim2.fromOffset(78, 58), "📌\nANCLAR", Color3.fromRGB(205, 150, 45) ) UI.buttons.forceDown = makeSmallButton( "ForceDown", UDim2.new(0, 12, 1, -220), UDim2.fromOffset(72, 50), "🎯 −", Color3.fromRGB(145, 70, 70) ) UI.buttons.forceUp = makeSmallButton( "ForceUp", UDim2.new(0, 92, 1, -220), UDim2.fromOffset(72, 50), "🎯 +", Color3.fromRGB(65, 150, 85) ) UI.buttons.magnet = makeSmallButton( "Magnet", UDim2.new(1, -92, 1, -220), UDim2.fromOffset(80, 50), "🧲 IMÁN", Color3.fromRGB(55, 130, 205) ) UI.buttons.rotation = makeSmallButton( "Rotation", UDim2.new(1, -178, 1, -220), UDim2.fromOffset(78, 50), "🔄 ROTAR", Color3.fromRGB(120, 85, 190) ) -------------------------------------------------- -- VALOR -------------------------------------------------- local valueLabel = Instance.new("TextLabel") valueLabel.Name = "Value" valueLabel.Size = UDim2.fromOffset(180, 42) valueLabel.Position = UDim2.new(0.5, -90, 1, -140) valueLabel.BackgroundColor3 = Color3.fromRGB(25, 25, 25) valueLabel.BackgroundTransparency = 0.18 valueLabel.TextScaled = true valueLabel.Font = Enum.Font.GothamBold valueLabel.TextColor3 = Color3.new(1, 1, 1) valueLabel.ZIndex = 9 makeCorner(valueLabel, 12) makeStroke(valueLabel, 0.8) valueLabel.Parent = panel UI.valueLabel = valueLabel -------------------------------------------------- -- IMÁN -------------------------------------------------- UI.magnetButtons = {} UI.magnetButtons.forceDown = makeSmallButton( "MagnetForceDown", UDim2.new(0, 12, 1, -220), UDim2.fromOffset(90, 55), "⚡ −", Color3.fromRGB(145, 70, 70) ) UI.magnetButtons.forceUp = makeSmallButton( "MagnetForceUp", UDim2.new(0, 108, 1, -220), UDim2.fromOffset(90, 55), "⚡ +", Color3.fromRGB(65, 150, 85) ) UI.magnetButtons.radiusDown = makeSmallButton( "RadiusDown", UDim2.new(1, -204, 1, -220), UDim2.fromOffset(90, 55), "📏 −", Color3.fromRGB(60, 135, 200) ) UI.magnetButtons.radiusUp = makeSmallButton( "RadiusUp", UDim2.new(1, -108, 1, -220), UDim2.fromOffset(90, 55), "📏 +", Color3.fromRGB(60, 135, 200) ) -------------------------------------------------- -- CAMBIO PEDIDO: -- DESACTIVAR ABAJO IZQUIERDA -------------------------------------------------- UI.magnetButtons.exit = makeSmallButton( "MagnetExit", UDim2.new(0, 20, 1, -105), UDim2.fromOffset(175, 58), "🧲 DESACTIVAR", Color3.fromRGB(180, 65, 65) ) -------------------------------------------------- -- CAMBIO PEDIDO: -- ANCLAR TODO ABAJO DERECHA -------------------------------------------------- UI.magnetButtons.massAnchor = makeSmallButton( "MassAnchor", UDim2.new(1, -195, 1, -105), UDim2.fromOffset(175, 58), "📌 ANCLAR TODO", Color3.fromRGB(200, 145, 35) ) -------------------------------------------------- -- ROTACIÓN -------------------------------------------------- UI.rotationButtons = {} -------------------------------------------------- -- CAMBIO PEDIDO: -- TODO EL PAD ABAJO IZQUIERDA -------------------------------------------------- UI.rotationButtons.up = makeSmallButton( "RotateUp", UDim2.new(0, 102, 1, -165), UDim2.fromOffset(62, 55), "▲", Color3.fromRGB(100, 80, 190) ) UI.rotationButtons.left = makeSmallButton( "RotateLeft", UDim2.new(0, 34, 1, -105), UDim2.fromOffset(62, 55), "◀", Color3.fromRGB(100, 80, 190) ) UI.rotationButtons.right = makeSmallButton( "RotateRight", UDim2.new(0, 170, 1, -105), UDim2.fromOffset(62, 55), "▶", Color3.fromRGB(100, 80, 190) ) UI.rotationButtons.down = makeSmallButton( "RotateDown", UDim2.new(0, 102, 1, -45), UDim2.fromOffset(62, 55), "▼", Color3.fromRGB(100, 80, 190) ) UI.rotationButtons.exit = makeSmallButton( "RotateExit", UDim2.new(1, -175, 1, -100), UDim2.fromOffset(155, 55), "✅ TERMINAR", Color3.fromRGB(65, 145, 90) ) -------------------------------------------------- -- OCULTAR MODOS AL INICIO -------------------------------------------------- for _, button in pairs(UI.magnetButtons) do button.Visible = false end for _, button in pairs(UI.rotationButtons) do button.Visible = false end end createMainGUI() if isMobile then createMobileUI() end -------------------------------------------------- -- NOTIFICACIONES -------------------------------------------------- local function notify(title, text, duration) if not STATE.active then return end local now = os.clock() if now - STATE.lastNotificationTime < STATE.notificationCooldown then return end STATE.lastNotificationTime = now pcall(function() StarterGui:SetCore( "SendNotification", { Title = title, Text = text, Duration = duration or 1.2, } ) end) end -------------------------------------------------- -- UTILIDADES -------------------------------------------------- local function isPlayerPart(part) if not part then return false end for _, otherPlayer in ipairs( Players:GetPlayers() ) do local character = otherPlayer.Character if character and part:IsDescendantOf(character) then return true end end return false end local function hasUnanchoredWeld(part) for _, connectedPart in ipairs( part:GetConnectedParts() ) do if connectedPart ~= part and not connectedPart.Anchored then return true end end return false end -------------------------------------------------- -- VISIBILIDAD DEL PERSONAJE -------------------------------------------------- local function hideCharacter() local character = player.Character if not character then return end if next( STATE.characterVisibilityBackup ) ~= nil then return end for _, object in ipairs( character:GetDescendants() ) do if object:IsA("BasePart") then STATE.characterVisibilityBackup[ object ] = object.LocalTransparencyModifier object.LocalTransparencyModifier = 1 elseif object:IsA("Decal") or object:IsA("Texture") then STATE.characterVisibilityBackup[ object ] = object.Transparency object.Transparency = 1 end end end local function showCharacter() for object, transparency in pairs( STATE.characterVisibilityBackup ) do if object and object:IsDescendantOf(workspace) then if object:IsA("BasePart") then object.LocalTransparencyModifier = transparency elseif object:IsA("Decal") or object:IsA("Texture") then object.Transparency = transparency end end end STATE.characterVisibilityBackup = {} end -------------------------------------------------- -- CONGELAR PERSONAJE -------------------------------------------------- local function freezeCharacter() if STATE.characterFrozen then return end local humanoid = getHumanoid() local root = getRootPart() if not humanoid or not root then return end STATE.characterBackup = { WalkSpeed = humanoid.WalkSpeed, JumpPower = humanoid.JumpPower, JumpHeight = humanoid.JumpHeight, AutoRotate = humanoid.AutoRotate, RootAnchored = root.Anchored, } STATE.characterFrozen = true humanoid.WalkSpeed = 0 humanoid.JumpPower = 0 humanoid.JumpHeight = 0 humanoid.AutoRotate = false root.AssemblyLinearVelocity = Vector3.zero root.AssemblyAngularVelocity = Vector3.zero root.Anchored = true end local function unfreezeCharacter() if not STATE.characterFrozen then return end local humanoid = getHumanoid() local root = getRootPart() local backup = STATE.characterBackup STATE.characterFrozen = false STATE.characterBackup = nil if humanoid and backup then humanoid.WalkSpeed = backup.WalkSpeed humanoid.JumpPower = backup.JumpPower humanoid.JumpHeight = backup.JumpHeight humanoid.AutoRotate = backup.AutoRotate end if root and backup then root.Anchored = backup.RootAnchored end end -------------------------------------------------- -- FÍSICA -------------------------------------------------- local function disconnectPhysics() bodyVelocity.Parent = nil bodyGyro.Parent = nil end local function connectPhysics(target) if not target then return end bodyVelocity.Parent = target bodyGyro.Parent = target end -------------------------------------------------- -- RAY -------------------------------------------------- local function getAimRay() if isMobile and UI.fakePointer then local position = UI.fakePointer.AbsolutePosition local size = UI.fakePointer.AbsoluteSize local x = position.X + size.X * 0.5 local y = position.Y + size.Y * 0.5 local ray = camera:ScreenPointToRay(x, y) return Ray.new( ray.Origin, ray.Direction * 1000 ) end local ray = camera:ScreenPointToRay( mouse.X, mouse.Y ) return Ray.new( ray.Origin, ray.Direction * 1000 ) end local function raycastNormal() local ray = getAimRay() return workspace:FindPartOnRayWithIgnoreList( ray, { getCharacter() } ) end local function raycastForMagnet() local ray = getAimRay() local ignoreList = { getCharacter() } for _ = 1, 100 do local hit, position, normal = workspace:FindPartOnRayWithIgnoreList( ray, ignoreList ) if not hit then return nil, nil, nil end if isPlayerPart(hit) then table.insert( ignoreList, hit ) elseif hit:IsA("BasePart") and not hit.Anchored then table.insert( ignoreList, hit ) else return hit, position, normal end end return nil, nil, nil end -------------------------------------------------- -- HIGHLIGHTS -------------------------------------------------- local function refreshHighlights() if not STATE.guiVisible then highlightHolding.Enabled = false highlightLooking.Enabled = false return end highlightHolding.Enabled = true highlightLooking.Enabled = true if STATE.holding and STATE.target then highlightHolding.Adornee = STATE.target highlightLooking.Adornee = nil elseif not STATE.holding then highlightHolding.Adornee = nil local hit = raycastNormal() if hit and hit:IsA("BasePart") and not hit.Anchored and not isPlayerPart(hit) then highlightLooking.Adornee = hit else highlightLooking.Adornee = nil end else highlightHolding.Adornee = nil highlightLooking.Adornee = nil end end -------------------------------------------------- -- MOSTRAR / OCULTAR UI -------------------------------------------------- local function setInterfaceVisible(visible) STATE.guiVisible = visible if not isMobile then if UI.forceLabel then UI.forceLabel.Visible = visible end if UI.rotationLabel then UI.rotationLabel.Visible = visible and STATE.rotationMode end else if UI.mobileContainer then UI.mobileContainer.Visible = visible end if UI.fakePointer then UI.fakePointer.Visible = visible end end -------------------------------------------------- -- EL CÍRCULO DEL IMÁN -- también depende de la visibilidad. -------------------------------------------------- if not visible then if usingDrawing and magnetCircle then magnetCircle.Visible = false elseif circleGui then circleGui.Enabled = false end end refreshHighlights() end local function toggleInterface() setInterfaceVisible( not STATE.guiVisible ) end -------------------------------------------------- -- MÓVIL: UI NORMAL -------------------------------------------------- local function updateMobileNormalUI() if not isMobile then return end STATE.mobileMode = "normal" UI.modeLabel.Text = "🎯 NORMAL" -------------------------------------------------- -- NORMAL -------------------------------------------------- UI.buttons.distanceDown.Visible = true UI.buttons.distanceUp.Visible = true UI.buttons.throw.Visible = true UI.buttons.anchor.Visible = true UI.buttons.forceDown.Visible = true UI.buttons.forceUp.Visible = true UI.buttons.magnet.Visible = true UI.buttons.rotation.Visible = true UI.actionButton.Visible = true UI.valueLabel.Visible = true -------------------------------------------------- -- OCULTAR OTROS MODOS -------------------------------------------------- for _, button in pairs( UI.magnetButtons ) do button.Visible = false end for _, button in pairs( UI.rotationButtons ) do button.Visible = false end -------------------------------------------------- -- VALOR -------------------------------------------------- UI.valueLabel.Text = "🎯 " .. math.floor( CONFIG.throwForce ) -------------------------------------------------- -- AGARRAR / SOLTAR -------------------------------------------------- if STATE.holding then UI.actionButton.Text = "❌ SOLTAR" UI.actionButton.BackgroundColor3 = Color3.fromRGB( 190, 55, 55 ) else UI.actionButton.Text = "✋ AGARRAR" UI.actionButton.BackgroundColor3 = Color3.fromRGB( 0, 190, 100 ) end refreshHighlights() end -------------------------------------------------- -- MÓVIL: UI IMÁN -------------------------------------------------- local function updateMobileMagnetUI() if not isMobile then return end STATE.mobileMode = "magnet" UI.modeLabel.Text = "🧲 MODO IMÁN" -------------------------------------------------- -- OCULTAR NORMAL -------------------------------------------------- UI.buttons.distanceDown.Visible = false UI.buttons.distanceUp.Visible = false UI.buttons.throw.Visible = false UI.buttons.anchor.Visible = false UI.buttons.forceDown.Visible = false UI.buttons.forceUp.Visible = false UI.buttons.magnet.Visible = false UI.buttons.rotation.Visible = false UI.actionButton.Visible = false -------------------------------------------------- -- MOSTRAR IMÁN -------------------------------------------------- for _, button in pairs( UI.magnetButtons ) do button.Visible = true end for _, button in pairs( UI.rotationButtons ) do button.Visible = false end -------------------------------------------------- -- VALOR -------------------------------------------------- UI.valueLabel.Visible = true UI.valueLabel.Text = "⚡ " .. math.floor( CONFIG.magnetForce ) .. " • 📏 " .. math.floor( CONFIG.magnetRadius ) end -------------------------------------------------- -- MÓVIL: UI ROTACIÓN -------------------------------------------------- local function updateMobileRotationUI() if not isMobile then return end STATE.mobileMode = "rotation" UI.modeLabel.Text = "🔄 MODO ROTACIÓN" -------------------------------------------------- -- OCULTAR NORMAL -------------------------------------------------- UI.buttons.distanceDown.Visible = false UI.buttons.distanceUp.Visible = false UI.buttons.throw.Visible = false UI.buttons.anchor.Visible = false UI.buttons.forceDown.Visible = false UI.buttons.forceUp.Visible = false UI.buttons.magnet.Visible = false UI.buttons.rotation.Visible = false UI.actionButton.Visible = false -------------------------------------------------- -- ROTACIÓN -------------------------------------------------- for _, button in pairs( UI.magnetButtons ) do button.Visible = false end for _, button in pairs( UI.rotationButtons ) do button.Visible = true end -------------------------------------------------- -- VALOR -------------------------------------------------- UI.valueLabel.Visible = true UI.valueLabel.Text = "↑ ↓ ← → • MANTÉN" end -------------------------------------------------- -- AGARRAR -------------------------------------------------- local function grabOrRelease() if not STATE.active then return end if STATE.magnetActive then return end if STATE.rotationMode then return end -------------------------------------------------- -- SOLTAR -------------------------------------------------- if STATE.holding then local target = STATE.target STATE.holding = false STATE.target = nil STATE.anchoredWhileHolding = false disconnectPhysics() if target and target:IsDescendantOf(workspace) then target.AssemblyLinearVelocity = Vector3.zero target.AssemblyAngularVelocity = Vector3.zero end if isMobile then updateMobileNormalUI() end return end -------------------------------------------------- -- AGARRAR -------------------------------------------------- local hit, position = raycastNormal() if not hit or not hit:IsA("BasePart") then return end if isPlayerPart(hit) then return end if hit.Anchored then if not hit:GetAttribute( "TelekinesisAnchored" ) then return end hit.Anchored = false hit:SetAttribute( "TelekinesisAnchored", nil ) end STATE.target = hit STATE.holding = true STATE.anchoredWhileHolding = false STATE.holdDistance = position and ( camera.CFrame.Position - position ).Magnitude or ( camera.CFrame.Position - hit.Position ).Magnitude bodyGyro.CFrame = hit.CFrame connectPhysics(hit) if isMobile then updateMobileNormalUI() end notify( "✋ AGARRADO", "", 0.5 ) end -------------------------------------------------- -- LANZAR -------------------------------------------------- local function throwObject() if not STATE.active or STATE.magnetActive or STATE.rotationMode then return end if not STATE.holding or not STATE.target then return end local target = STATE.target STATE.holding = false STATE.target = nil STATE.anchoredWhileHolding = false disconnectPhysics() if target and target:IsDescendantOf(workspace) then target.Anchored = false local ray = getAimRay() local velocity = Instance.new("BodyVelocity") velocity.Name = "TelekinesisThrow" velocity.MaxForce = Vector3.new(1, 1, 1) * 1e6 velocity.P = CONFIG.holdVelocityP velocity.Velocity = ray.Direction.Unit * CONFIG.throwForce velocity.Parent = target Debris:AddItem( velocity, 0.5 ) end if isMobile then updateMobileNormalUI() end notify( "🔥 LANZADO", "", 0.5 ) end -------------------------------------------------- -- ANCLAR -------------------------------------------------- local function toggleAnchored() if not STATE.active or STATE.magnetActive or STATE.rotationMode then return end if not STATE.holding or not STATE.target then return end local target = STATE.target STATE.anchoredWhileHolding = not STATE.anchoredWhileHolding target.Anchored = STATE.anchoredWhileHolding if STATE.anchoredWhileHolding then target:SetAttribute( "TelekinesisAnchored", true ) target.AssemblyLinearVelocity = Vector3.zero target.AssemblyAngularVelocity = Vector3.zero disconnectPhysics() else target:SetAttribute( "TelekinesisAnchored", nil ) connectPhysics(target) end notify( STATE.anchoredWhileHolding and "📌 ANCLADO" or "📎 DESANCLADO", "", 0.5 ) end -------------------------------------------------- -- ROTACIÓN -------------------------------------------------- local function resetRotationKeys() STATE.rotationKeys.up = false STATE.rotationKeys.down = false STATE.rotationKeys.left = false STATE.rotationKeys.right = false end local function enterRotationMode() if not STATE.holding or not STATE.target then notify( "❌ NO DISPONIBLE", "Debes agarrar un objeto primero", 2 ) return end if STATE.anchoredWhileHolding then notify( "❌ OBJETO ANCLADO", "Desancla el objeto antes de rotarlo", 2 ) return end local target = STATE.target STATE.rotationMode = true STATE.rotationPosition = target.Position resetRotationKeys() bodyVelocity.Parent = nil bodyGyro.Parent = nil rotationPositionLock.Position = STATE.rotationPosition rotationPositionLock.Parent = target target.AssemblyLinearVelocity = Vector3.zero target.AssemblyAngularVelocity = Vector3.zero freezeCharacter() hideCharacter() if isMobile then updateMobileRotationUI() else if UI.rotationLabel then UI.rotationLabel.Visible = STATE.guiVisible end if UI.forceLabel then UI.forceLabel.Visible = false end end notify( "🔄 MODO ROTACIÓN", "W/A/S/D o flechas", 1.5 ) end local function exitRotationMode() if not STATE.rotationMode then return end local target = STATE.target STATE.rotationMode = false resetRotationKeys() rotationPositionLock.Parent = nil STATE.rotationPosition = nil showCharacter() unfreezeCharacter() if target and target:IsDescendantOf(workspace) then if not STATE.anchoredWhileHolding then connectPhysics(target) bodyGyro.CFrame = target.CFrame end end if isMobile then updateMobileNormalUI() else if UI.rotationLabel then UI.rotationLabel.Visible = STATE.guiVisible and false end if UI.forceLabel and STATE.guiVisible then UI.forceLabel.Visible = true end end notify( "🔄 ROTACIÓN TERMINADA", "", 0.7 ) end local function toggleRotationMode() if STATE.rotationMode then exitRotationMode() else enterRotationMode() end end -------------------------------------------------- -- ACTUALIZAR ROTACIÓN -------------------------------------------------- local function updateRotation() if not STATE.rotationMode or not STATE.target then return end local target = STATE.target if STATE.rotationPosition then rotationPositionLock.Position = STATE.rotationPosition end local horizontal = 0 local vertical = 0 if STATE.rotationKeys.left then horizontal -= 1 end if STATE.rotationKeys.right then horizontal += 1 end if STATE.rotationKeys.up then vertical += 1 end if STATE.rotationKeys.down then vertical -= 1 end if horizontal == 0 and vertical == 0 then target.AssemblyLinearVelocity = Vector3.zero target.AssemblyAngularVelocity = Vector3.zero return end if horizontal ~= 0 then target.CFrame = target.CFrame * CFrame.Angles( 0, math.rad( horizontal * CONFIG.rotationSpeed ), 0 ) end if vertical ~= 0 then target.CFrame = target.CFrame * CFrame.Angles( math.rad( -vertical * CONFIG.rotationSpeed ), 0, 0 ) end target.AssemblyLinearVelocity = Vector3.zero target.AssemblyAngularVelocity = Vector3.zero end -------------------------------------------------- -- IMÁN -------------------------------------------------- local function restoreMagnetPhysics() for object in pairs( STATE.magnetObjects ) do if object and object:IsDescendantOf(workspace) then local bv = object:FindFirstChild("ImanBV") if bv then bv:Destroy() end end end STATE.magnetObjects = {} end local function massAnchorMagnet() if not STATE.active or not STATE.magnetActive then return end local count = 0 for object in pairs( STATE.magnetObjects ) do if object and object:IsDescendantOf(workspace) then object.Anchored = true object:SetAttribute( "TelekinesisAnchored", true ) local bv = object:FindFirstChild("ImanBV") if bv then bv:Destroy() end count += 1 end end STATE.magnetObjects = {} notify( "📌 ANCLAJE MASIVO", "Se anclaron " .. count .. " objetos", 1.5 ) end local function activateMagnet() if not STATE.active then return end if STATE.holding then notify( "❌ NO DISPONIBLE", "Suelta el objeto para usar el imán", 2 ) return end if STATE.rotationMode then return end STATE.magnetActive = true if isMobile then updateMobileMagnetUI() end notify( "🧲 IMÁN ACTIVADO", "Las piezas no ancladas se atraviesan", 1.5 ) end local function deactivateMagnet() STATE.magnetActive = false restoreMagnetPhysics() if isMobile then updateMobileNormalUI() end notify( "🧲 IMÁN DESACTIVADO", "", 0.7 ) end local function toggleMagnet() if STATE.magnetActive then deactivateMagnet() else activateMagnet() end end -------------------------------------------------- -- FUERZA -------------------------------------------------- local function changeThrowForce(amount) CONFIG.throwForce = math.clamp( CONFIG.throwForce + amount, CONFIG.throwForceMin, CONFIG.throwForceMax ) if isMobile and STATE.mobileMode == "normal" then updateMobileNormalUI() end notify( "🎯 FUERZA", tostring( math.floor( CONFIG.throwForce ) ), 0.5 ) end local function changeMagnetForce(amount) CONFIG.magnetForce = math.clamp( CONFIG.magnetForce + amount, CONFIG.magnetForceMin, CONFIG.magnetForceMax ) if isMobile and STATE.mobileMode == "magnet" then updateMobileMagnetUI() end end local function changeMagnetRadius(amount) CONFIG.magnetRadius = math.clamp( CONFIG.magnetRadius + amount, CONFIG.magnetRadiusMin, CONFIG.magnetRadiusMax ) if isMobile and STATE.mobileMode == "magnet" then updateMobileMagnetUI() end end -------------------------------------------------- -- DISTANCIA -------------------------------------------------- local function updateDistance(delta) if STATE.rotationMode then return end if STATE.magnetActive then changeMagnetRadius(delta) return end if not STATE.holding then return end STATE.holdDistance = math.clamp( STATE.holdDistance + delta, CONFIG.holdDistanceMin, CONFIG.holdDistanceMax ) end -------------------------------------------------- -- PC INPUT -------------------------------------------------- UserInputService.InputBegan:Connect( function(input, gameProcessed) if not STATE.active or gameProcessed then return end if input.UserInputType == Enum.UserInputType.Keyboard then local key = input.KeyCode -------------------------------------------------- -- ROTACIÓN -------------------------------------------------- if STATE.rotationMode then if key == Enum.KeyCode.C then exitRotationMode() return end if key == Enum.KeyCode.W or key == Enum.KeyCode.Up then STATE.rotationKeys.up = true return end if key == Enum.KeyCode.S or key == Enum.KeyCode.Down then STATE.rotationKeys.down = true return end if key == Enum.KeyCode.A or key == Enum.KeyCode.Left then STATE.rotationKeys.left = true return end if key == Enum.KeyCode.D or key == Enum.KeyCode.Right then STATE.rotationKeys.right = true return end return end -------------------------------------------------- -- NORMAL -------------------------------------------------- if key == Enum.KeyCode.Q then STATE.holdQ = true elseif key == Enum.KeyCode.E then STATE.holdE = true elseif key == Enum.KeyCode.R then if STATE.magnetActive then massAnchorMagnet() else toggleAnchored() end elseif key == Enum.KeyCode.F then throwObject() elseif key == Enum.KeyCode.C then toggleRotationMode() elseif key == Enum.KeyCode.T then toggleMagnet() elseif key == Enum.KeyCode.Z then if STATE.magnetActive then changeMagnetForce( -CONFIG.magnetForceStep ) else changeThrowForce( -CONFIG.throwForceStepPC ) end elseif key == Enum.KeyCode.X then if STATE.magnetActive then changeMagnetForce( CONFIG.magnetForceStep ) else changeThrowForce( CONFIG.throwForceStepPC ) end elseif key == Enum.KeyCode.RightControl then toggleInterface() elseif key == Enum.KeyCode.LeftControl then notify( "⌨️ CONTROLES", "Click = Agarrar\n" .. "F = Lanzar\n" .. "Q/E = Distancia\n" .. "R = Anclar\n" .. "T = Imán\n" .. "C = Rotación\n" .. "Ctrl derecho = Mostrar/Ocultar", 7 ) elseif key == Enum.KeyCode.LeftAlt or key == Enum.KeyCode.RightAlt then notify( "⌨️ ROTACIÓN", "W/A/S/D o flechas", 2 ) end elseif input.UserInputType == Enum.UserInputType.MouseButton1 then grabOrRelease() end end ) -------------------------------------------------- -- PC INPUT END -------------------------------------------------- UserInputService.InputEnded:Connect( function(input) if not STATE.active then return end if input.UserInputType == Enum.UserInputType.Keyboard then local key = input.KeyCode if STATE.rotationMode then if key == Enum.KeyCode.W or key == Enum.KeyCode.Up then STATE.rotationKeys.up = false elseif key == Enum.KeyCode.S or key == Enum.KeyCode.Down then STATE.rotationKeys.down = false elseif key == Enum.KeyCode.A or key == Enum.KeyCode.Left then STATE.rotationKeys.left = false elseif key == Enum.KeyCode.D or key == Enum.KeyCode.Right then STATE.rotationKeys.right = false end return end if key == Enum.KeyCode.Q then STATE.holdQ = false elseif key == Enum.KeyCode.E then STATE.holdE = false end end end ) -------------------------------------------------- -- MÓVIL: HELPERS -------------------------------------------------- local function connectTap( button, callback ) button.Activated:Connect( function() if not STATE.active then return end callback() end ) end local function connectHold( button, onBegin, onEnd ) local activeInput = nil button.InputBegan:Connect( function(input) if not STATE.active then return end if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then activeInput = input onBegin() end end ) button.InputEnded:Connect( function(input) if input == activeInput then activeInput = nil onEnd() end end ) end -------------------------------------------------- -- MÓVIL: BOTONES -------------------------------------------------- if isMobile and UI.buttons then local b = UI.buttons -------------------------------------------------- -- AGARRAR -------------------------------------------------- connectTap( UI.actionButton, function() grabOrRelease() end ) -------------------------------------------------- -- LANZAR -------------------------------------------------- connectTap( b.throw, function() throwObject() end ) -------------------------------------------------- -- ANCLAR -------------------------------------------------- connectTap( b.anchor, function() toggleAnchored() end ) -------------------------------------------------- -- DISTANCIA -------------------------------------------------- connectHold( b.distanceDown, function() STATE.holdClose = true end, function() STATE.holdClose = false end ) connectHold( b.distanceUp, function() STATE.holdFar = true end, function() STATE.holdFar = false end ) -------------------------------------------------- -- FUERZA -------------------------------------------------- connectTap( b.forceDown, function() changeThrowForce( -CONFIG.throwForceStepMobile ) end ) connectTap( b.forceUp, function() changeThrowForce( CONFIG.throwForceStepMobile ) end ) -------------------------------------------------- -- IMÁN -------------------------------------------------- connectTap( b.magnet, function() activateMagnet() end ) -------------------------------------------------- -- ROTACIÓN -------------------------------------------------- connectTap( b.rotation, function() enterRotationMode() end ) -------------------------------------------------- -- OJO -------------------------------------------------- connectTap( UI.hideButton, function() setInterfaceVisible(false) end ) -------------------------------------------------- -- IMÁN -------------------------------------------------- local mb = UI.magnetButtons connectTap( mb.forceDown, function() changeMagnetForce( -CONFIG.magnetForceStep ) end ) connectTap( mb.forceUp, function() changeMagnetForce( CONFIG.magnetForceStep ) end ) connectTap( mb.radiusDown, function() changeMagnetRadius( -CONFIG.magnetRadiusStep ) end ) connectTap( mb.radiusUp, function() changeMagnetRadius( CONFIG.magnetRadiusStep ) end ) connectTap( mb.massAnchor, function() massAnchorMagnet() end ) connectTap( mb.exit, function() deactivateMagnet() end ) -------------------------------------------------- -- ROTACIÓN -------------------------------------------------- local rb = UI.rotationButtons connectHold( rb.up, function() STATE.rotationKeys.up = true end, function() STATE.rotationKeys.up = false end ) connectHold( rb.down, function() STATE.rotationKeys.down = true end, function() STATE.rotationKeys.down = false end ) connectHold( rb.left, function() STATE.rotationKeys.left = true end, function() STATE.rotationKeys.left = false end ) connectHold( rb.right, function() STATE.rotationKeys.right = true end, function() STATE.rotationKeys.right = false end ) connectTap( rb.exit, function() exitRotationMode() end ) end -------------------------------------------------- -- BOTÓN DE MOSTRAR MÓVIL -- -- ES UN SOLO BOTÓN PERSISTENTE -- ARRIBA A LA IZQUIERDA. -------------------------------------------------- if isMobile then local showButton = Instance.new("TextButton") showButton.Name = "ShowInterface" showButton.Size = UDim2.fromOffset(55, 55) showButton.Position = UDim2.fromOffset(15, 15) showButton.BackgroundColor3 = Color3.fromRGB(35, 35, 35) showButton.BackgroundTransparency = 0.2 showButton.Text = "👁️" showButton.TextScaled = true showButton.Font = Enum.Font.GothamBold showButton.TextColor3 = Color3.new(1, 1, 1) showButton.Visible = false showButton.ZIndex = 200 styleButton(showButton) showButton.Parent = UI.mobileGui UI.showButton = showButton showButton.Activated:Connect( function() setInterfaceVisible(true) showButton.Visible = false if STATE.mobileMode == "magnet" and STATE.magnetActive then updateMobileMagnetUI() elseif STATE.mobileMode == "rotation" and STATE.rotationMode then updateMobileRotationUI() else updateMobileNormalUI() end end ) -------------------------------------------------- -- SOBREESCRIBIR OCULTAR: -- Mostrar botón arriba izquierda. -------------------------------------------------- UI.hideButton.Activated:Connect( function() setInterfaceVisible(false) showButton.Visible = true end ) end -------------------------------------------------- -- CURSOR MÓVIL -------------------------------------------------- if isMobile and UI.fakePointer then UI.fakePointer.InputBegan:Connect( function(input) if input.UserInputType ~= Enum.UserInputType.Touch then return end STATE.pointerTouch = input STATE.pointerTouchStart = input.Position STATE.pointerDragStarted = false end ) UserInputService.InputChanged:Connect( function(input) if input.UserInputType ~= Enum.UserInputType.Touch then return end if input ~= STATE.pointerTouch then return end if not STATE.pointerTouchStart then return end local delta = input.Position - STATE.pointerTouchStart if not STATE.pointerDragStarted then if delta.Magnitude < CONFIG.pointerDragThreshold then return end STATE.pointerDragStarted = true end UI.fakePointer.Position = UDim2.fromOffset( input.Position.X, input.Position.Y ) end ) UserInputService.InputEnded:Connect( function(input) if input ~= STATE.pointerTouch then return end STATE.pointerTouch = nil STATE.pointerTouchStart = nil STATE.pointerDragStarted = false end ) UserInputService.TouchEnded:Connect( function(input) if input ~= STATE.pointerTouch then return end STATE.pointerTouch = nil STATE.pointerTouchStart = nil STATE.pointerDragStarted = false end ) end -------------------------------------------------- -- RENDER -------------------------------------------------- RunService.RenderStepped:Connect( function() if not STATE.active then return end -------------------------------------------------- -- ROTACIÓN -------------------------------------------------- updateRotation() -------------------------------------------------- -- HIGHLIGHTS -------------------------------------------------- refreshHighlights() -------------------------------------------------- -- IMÁN VISUAL -------------------------------------------------- if STATE.magnetActive and not STATE.rotationMode and STATE.guiVisible then local hit, position = raycastForMagnet() if hit and position then surfacePosition = surfacePosition:Lerp( position, 0.35 ) else local ray = getAimRay() surfacePosition = surfacePosition:Lerp( ray.Origin + ray.Direction * 15, 0.15 ) end actualMagnetRadius += ( CONFIG.magnetRadius - actualMagnetRadius ) * 0.25 local percent = ( CONFIG.magnetForce - CONFIG.magnetForceMin ) / ( CONFIG.magnetForceMax - CONFIG.magnetForceMin ) local colorScale = Color3.fromHSV( 0.58 + percent * 0.3, 1, 1 ) if usingDrawing and magnetCircle then local viewport = camera:WorldToViewportPoint( surfacePosition ) magnetCircle.Visible = true magnetCircle.Position = Vector2.new( viewport.X, viewport.Y ) magnetCircle.Radius = actualMagnetRadius magnetCircle.Color = colorScale elseif circleGui then circleGui.Enabled = true circleGui.Size = UDim2.fromOffset( actualMagnetRadius * 2, actualMagnetRadius * 2 ) circleGui.Position = surfacePosition circleImage.ImageColor3 = colorScale end if UI.forceLabel and STATE.guiVisible and not isMobile then UI.forceLabel.Visible = true UI.forceLabel.Text = "🧲 Fuerza: " .. math.floor( CONFIG.magnetForce ) .. "\n📏 Radio: " .. math.floor( CONFIG.magnetRadius ) end elseif not STATE.rotationMode and STATE.guiVisible then if usingDrawing and magnetCircle then magnetCircle.Visible = false elseif circleGui then circleGui.Enabled = false end if UI.forceLabel and not isMobile then UI.forceLabel.Visible = true UI.forceLabel.Text = "🎯 Lanzamiento: " .. math.floor( CONFIG.throwForce ) end else if usingDrawing and magnetCircle then magnetCircle.Visible = false elseif circleGui then circleGui.Enabled = false end if UI.forceLabel then UI.forceLabel.Visible = false end end -------------------------------------------------- -- DISTANCIA -------------------------------------------------- if STATE.holding and not STATE.rotationMode and not STATE.magnetActive then if STATE.holdClose then updateDistance( -CONFIG.distanceSpeed ) end if STATE.holdFar then updateDistance( CONFIG.distanceSpeed ) end end end ) -------------------------------------------------- -- HEARTBEAT -------------------------------------------------- RunService.Heartbeat:Connect( function() if not STATE.active then return end -------------------------------------------------- -- OBJETO -------------------------------------------------- if STATE.holding and STATE.target then local target = STATE.target if STATE.rotationMode then target.AssemblyLinearVelocity = Vector3.zero target.AssemblyAngularVelocity = Vector3.zero if STATE.rotationPosition then rotationPositionLock.Position = STATE.rotationPosition end elseif not STATE.anchoredWhileHolding then local ray = getAimRay() local desiredPosition = ray.Origin + ray.Direction.Unit * STATE.holdDistance bodyVelocity.Velocity = ( desiredPosition - target.Position ) * 5 bodyGyro.CFrame = target.CFrame else target.AssemblyLinearVelocity = Vector3.zero target.AssemblyAngularVelocity = Vector3.zero end end -------------------------------------------------- -- IMÁN -------------------------------------------------- if STATE.magnetActive and not STATE.rotationMode then local center = surfacePosition local newObjects = {} local scaledForce = CONFIG.magnetForce * ( CONFIG.magnetRadius / 30 ) ^ 1.5 local diameter = CONFIG.magnetRadius * 2 local nearby = workspace:GetPartBoundsInBox( CFrame.new(center), Vector3.new( diameter, diameter, diameter ) ) for _, object in ipairs( nearby ) do if object:IsA("BasePart") and not object.Anchored and not isPlayerPart(object) and not hasUnanchoredWeld(object) and object.Transparency < 1 and object.CanCollide and object ~= STATE.target then local offset = center - object.Position local distance = offset.Magnitude if distance <= CONFIG.magnetRadius and distance > 0.01 then local velocity = object:FindFirstChild( "ImanBV" ) if not velocity then velocity = Instance.new( "BodyVelocity" ) velocity.Name = "ImanBV" velocity.MaxForce = Vector3.new( 1, 1, 1 ) * 1e5 velocity.P = 15000 velocity.Parent = object end velocity.Velocity = offset.Unit * scaledForce newObjects[object] = true end end end for object in pairs( STATE.magnetObjects ) do if not newObjects[object] then local bv = object and object:FindFirstChild( "ImanBV" ) if bv then bv:Destroy() end end end STATE.magnetObjects = newObjects else restoreMagnetPhysics() end -------------------------------------------------- -- Q / E PC -------------------------------------------------- if not STATE.rotationMode then if STATE.magnetActive then if STATE.holdQ then changeMagnetRadius( -CONFIG.magnetRadiusStep ) end if STATE.holdE then changeMagnetRadius( CONFIG.magnetRadiusStep ) end else if STATE.holdQ then updateDistance( -CONFIG.distanceKeySpeed ) end if STATE.holdE then updateDistance( CONFIG.distanceKeySpeed ) end end end end ) -------------------------------------------------- -- RESPAWN -------------------------------------------------- player.CharacterAdded:Connect( function() STATE.characterFrozen = false STATE.characterBackup = nil STATE.characterVisibilityBackup = {} if STATE.rotationMode then STATE.rotationMode = false resetRotationKeys() rotationPositionLock.Parent = nil end end ) -------------------------------------------------- -- INICIO -------------------------------------------------- if isMobile then updateMobileNormalUI() UI.showButton.Visible = false else if UI.forceLabel then UI.forceLabel.Visible = true end end print( "[Telekinesis V4.4] " .. "UI toggle corregido + " .. "Ctrl derecho + " .. "layouts de modos ajustados" )