-- // Delta Executor - Drone com Comando Estilo DJI RC (v3 com Térmico e Bombas) -- Só toque (telemóvel): joystick esquerdo = altura/girar | joystick direito = mover local Players = game:GetService("Players") local RunService = game:GetService("RunService") local Workspace = game:GetService("Workspace") local UserInputService = game:GetService("UserInputService") local TweenService = game:GetService("TweenService") local Lighting = game:GetService("Lighting") -- Se executares o script outra vez, limpa a versão anterior local env = (getgenv and getgenv()) or _G if env.__DroneCleanup then pcall(env.__DroneCleanup) end local player = Players.LocalPlayer local character = player.Character or player.CharacterAdded:Wait() local rootPart = character:WaitForChild("HumanoidRootPart") local camera = Workspace.CurrentCamera if Workspace:FindFirstChild("RealisticDroneModel") then Workspace.RealisticDroneModel:Destroy() end if player.PlayerGui:FindFirstChild("DJIRCControlGui") then player.PlayerGui.DJIRCControlGui:Destroy() end -- Configuração local SPEED, VSPEED, YAW_SPEED = 40, 25, 2.2 local DEFAULT_FOV = 70 -- Estado local conns = {} local flying, mode = false, "manual" -- manual | takeoff | rth | follow | land local battery = 100 local yaw = 0 local curVel = Vector3.zero local curTiltF, curTiltS = 0, 0 local rotorSpeed, rotorAngle = 0, 0 local cameraAttached, recording, recTime = false, false, 0 local fov = DEFAULT_FOV local stickL, stickR = Vector2.zero, Vector2.zero local rotors = {} -- Efeitos extra local thermalOn = false local colorCorrection = Instance.new("ColorCorrectionEffect") local function getHumanoid() return character and character:FindFirstChildOfClass("Humanoid") end --------------------------------------------------------------------- -- 1. Modelo do drone --------------------------------------------------------------------- local droneModel = Instance.new("Model") droneModel.Name = "RealisticDroneModel" droneModel.Parent = Workspace local dronePart = Instance.new("Part") dronePart.Name = "DroneCore" dronePart.Size = Vector3.new(2, 0.6, 2.5) dronePart.Material = Enum.Material.SmoothPlastic dronePart.Color = Color3.fromRGB(55, 60, 65) dronePart.CanCollide = false dronePart.Parent = droneModel droneModel.PrimaryPart = dronePart -- Raycast para descobrir o chão local rayParams = RaycastParams.new() rayParams.FilterType = Enum.RaycastFilterType.Exclude rayParams.FilterDescendantsInstances = {droneModel, character} local function groundY(pos) local r = Workspace:Raycast(pos + Vector3.new(0, 1, 0), Vector3.new(0, -1000, 0), rayParams) return r and r.Position.Y or nil end -- Posição inicial: no chão, à frente do jogador local look = rootPart.CFrame.LookVector local startPos = rootPart.Position + look * 4 local startGround = groundY(startPos + Vector3.new(0, 5, 0)) yaw = math.atan2(-look.X, -look.Z) dronePart.CFrame = CFrame.new(startPos.X, (startGround or (rootPart.Position.Y - 2.5)) + 0.9, startPos.Z) * CFrame.Angles(0, yaw, 0) local function weldTo(p0, p1) local w = Instance.new("Weld") w.Part0 = p0 w.Part1 = p1 w.C0 = p0.CFrame:ToObjectSpace(p1.CFrame) w.Parent = p0 return w end local function addPart(size, offset, color, material, shape) local p = Instance.new("Part") p.Size = size p.CFrame = dronePart.CFrame * offset p.Color = color p.Material = material or Enum.Material.SmoothPlastic if shape then p.Shape = shape end p.CanCollide = false p.Massless = true p.Parent = droneModel return p, weldTo(dronePart, p) end -- Câmara gimbal e sensores addPart(Vector3.new(0.6, 0.5, 0.6), CFrame.new(0, -0.4, -1.2), Color3.fromRGB(20, 20, 20), Enum.Material.Metal) addPart(Vector3.new(0.4, 0.4, 0.3), CFrame.new(0, -0.4, -1.45), Color3.fromRGB(0, 170, 255), Enum.Material.Glass) addPart(Vector3.new(1.2, 0.3, 0.4), CFrame.new(0, 0.1, -1.25), Color3.fromRGB(35, 35, 35)) -- Luz do drone local lightColors = { Color3.fromRGB(0, 255, 255), Color3.fromRGB(0, 255, 120), Color3.fromRGB(255, 60, 60), Color3.fromRGB(180, 80, 255), Color3.fromRGB(255, 255, 255), } local lightIdx = 1 local lightOn = true local lightPart = addPart(Vector3.new(0.4, 0.1, 0.4), CFrame.new(0, 0.35, 1.3), lightColors[1], Enum.Material.Neon) local light = Instance.new("PointLight") light.Color = lightColors[1] light.Range = 15 light.Brightness = 4 light.Parent = lightPart -- Braços, motores e hélices for _, sx in ipairs({-1, 1}) do for _, sz in ipairs({-1, 1}) do local corner = Vector3.new(sx * 1.7, 0, sz * 1.7) addPart(Vector3.new(0.3, 0.15, corner.Magnitude), CFrame.lookAt(corner / 2, corner), Color3.fromRGB(70, 75, 80)) addPart(Vector3.new(0.4, 0.6, 0.6), CFrame.new(corner + Vector3.new(0, 0.2, 0)) * CFrame.Angles(0, 0, math.rad(90)), Color3.fromRGB(30, 30, 30), Enum.Material.Metal, Enum.PartType.Cylinder) local blade, bw = addPart(Vector3.new(2.2, 0.05, 0.25), CFrame.new(corner + Vector3.new(0, 0.45, 0)) * CFrame.Angles(0, math.rad(45), 0), Color3.fromRGB(240, 130, 0), Enum.Material.Neon) table.insert(rotors, {weld = bw, base = bw.C0, dir = (sx * sz > 0) and 1 or -1}) end end local bv = Instance.new("BodyVelocity") bv.MaxForce = Vector3.new(math.huge, math.huge, math.huge) bv.Velocity = Vector3.zero bv.Parent = dronePart local bg = Instance.new("BodyGyro") bg.MaxTorque = Vector3.new(math.huge, math.huge, math.huge) bg.CFrame = dronePart.CFrame bg.Parent = dronePart --------------------------------------------------------------------- -- 2. Interface (Comando com mais espaço para os novos botões) --------------------------------------------------------------------- local function make(class, props, parent) local o = Instance.new(class) for k, v in pairs(props) do o[k] = v end o.Parent = parent return o end local function roundify(o, r) make("UICorner", {CornerRadius = UDim.new(0, r)}, o) end local screenGui = make("ScreenGui", { Name = "DJIRCControlGui", ResetOnSpawn = false, IgnoreGuiInset = true, }, player:WaitForChild("PlayerGui")) -- Corpo do comando (ligeiramente mais alto para caber tudo) local rcFrame = make("Frame", { Size = UDim2.new(0, 300, 0, 244), Position = UDim2.new(0, 10, 0, 50), BackgroundColor3 = Color3.fromRGB(45, 48, 55), BorderSizePixel = 0, }, screenGui) roundify(rcFrame, 14) local topBar = make("Frame", { Size = UDim2.new(1, 0, 0, 28), BackgroundColor3 = Color3.fromRGB(35, 38, 44), BorderSizePixel = 0, }, rcFrame) roundify(topBar, 14) local ledStatus = make("TextLabel", { Size = UDim2.new(1, -34, 1, 0), BackgroundTransparency = 1, Text = "🔋 100% [ DJI RC - LINKED ]", TextColor3 = Color3.fromRGB(0, 255, 120), TextSize = 11, Font = Enum.Font.Code, }, topBar) local btnClose = make("TextButton", { Size = UDim2.new(0, 24, 0, 24), Position = UDim2.new(1, -28, 0, 2), BackgroundColor3 = Color3.fromRGB(120, 30, 30), TextColor3 = Color3.new(1, 1, 1), Text = "X", TextSize = 10, Font = Enum.Font.GothamBold, }, topBar) roundify(btnClose, 4) -- Ecrã do comando (telemetria) local screenDisplay = make("Frame", { Size = UDim2.new(1, -20, 0, 66), Position = UDim2.new(0, 10, 0, 34), BackgroundColor3 = Color3.fromRGB(15, 15, 20), BorderSizePixel = 0, }, rcFrame) roundify(screenDisplay, 8) local screenLabel = make("TextLabel", { Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, Text = "🏔️ DRONE 4K\n[ Pronto para descolar ]", TextColor3 = Color3.fromRGB(200, 220, 255), TextSize = 12, Font = Enum.Font.GothamBold, }, screenDisplay) -- Botões Grid local btnContainer = make("Frame", { Size = UDim2.new(1, -16, 0, 132), Position = UDim2.new(0, 8, 0, 106), BackgroundTransparency = 1, }, rcFrame) make("UIGridLayout", { CellSize = UDim2.new(0, 66, 0, 28), CellPadding = UDim2.new(0, 5, 0, 4), SortOrder = Enum.SortOrder.LayoutOrder, }, btnContainer) local btns, btnColors = {}, {} local GRAY = Color3.fromRGB(80, 85, 95) local function createRcBtn(name, text, off, on, order) local b = make("TextButton", { BackgroundColor3 = off, TextColor3 = Color3.new(1, 1, 1), Text = text, TextSize = 10, Font = Enum.Font.GothamBold, LayoutOrder = order, }, btnContainer) roundify(b, 6) btns[name] = b btnColors[b] = {off = off, on = on or off} return b end local function setBtn(b, isOn) b.BackgroundColor3 = isOn and btnColors[b].on or btnColors[b].off end createRcBtn("fly", "🚀 Voar", Color3.fromRGB(0, 110, 200), Color3.fromRGB(0, 180, 90), 1) createRcBtn("cam", "👁️ Câmara", Color3.fromRGB(40, 140, 70), Color3.fromRGB(200, 90, 0), 2) createRcBtn("rth", "🏠 Casa", Color3.fromRGB(0, 120, 130), Color3.fromRGB(0, 200, 210), 3) createRcBtn("follow", "🎯 Seguir", Color3.fromRGB(110, 60, 170), Color3.fromRGB(170, 90, 240), 4) createRcBtn("zin", "➕ Zoom", GRAY, nil, 5) createRcBtn("zout", "➖ Zoom", GRAY, nil, 6) createRcBtn("photo", "📸 Foto", GRAY, nil, 7) createRcBtn("rec", "🔴 REC", Color3.fromRGB(120, 40, 40), Color3.fromRGB(220, 30, 30), 8) createRcBtn("light", "💡 Luz", Color3.fromRGB(150, 120, 0), Color3.fromRGB(230, 190, 0), 9) createRcBtn("color", "🎨 Cor", GRAY, nil, 10) createRcBtn("thermal", "🌡️ Térmico", Color3.fromRGB(40, 40, 80), Color3.fromRGB(255, 100, 0), 11) createRcBtn("drop", "📦 Largar", Color3.fromRGB(130, 70, 0), Color3.fromRGB(200, 110, 0), 12) createRcBtn("pull", "📍 Puxar", Color3.fromRGB(180, 110, 0), nil, 13) createRcBtn("boom", "💥 Explodir", Color3.fromRGB(180, 40, 40), nil, 14) setBtn(btns.light, true) -- HUD de visão em primeira pessoa local hudGui = make("Frame", { Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, Visible = false, }, screenGui) make("TextLabel", { Size = UDim2.new(0, 40, 0, 40), AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), BackgroundTransparency = 1, Text = "+", TextColor3 = Color3.fromRGB(0, 255, 100), TextSize = 35, Font = Enum.Font.Code, }, hudGui) local hudRec = make("TextLabel", { Size = UDim2.new(0, 220, 0, 28), AnchorPoint = Vector2.new(0.5, 0), Position = UDim2.new(0.5, 0, 0, 50), BackgroundColor3 = Color3.new(0, 0, 0), BackgroundTransparency = 0.4, TextColor3 = Color3.fromRGB(0, 255, 100), Text = "[ ⏺ STANDBY ]", TextSize = 12, Font = Enum.Font.Code, }, hudGui) roundify(hudRec, 6) local hudTelemetry = make("TextLabel", { Size = UDim2.new(0, 260, 0, 40), AnchorPoint = Vector2.new(0.5, 1), Position = UDim2.new(0.5, 0, 1, -12), BackgroundColor3 = Color3.new(0, 0, 0), BackgroundTransparency = 0.4, TextColor3 = Color3.fromRGB(0, 255, 100), Text = "", TextSize = 11, Font = Enum.Font.Code, }, hudGui) roundify(hudTelemetry, 6) -- Flash de foto e aviso local flash = make("Frame", { Size = UDim2.new(1, 0, 1, 0), BackgroundColor3 = Color3.new(1, 1, 1), BackgroundTransparency = 1, BorderSizePixel = 0, ZIndex = 10, }, screenGui) local toastLabel = make("TextLabel", { Size = UDim2.new(0, 220, 0, 30), AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.7, 0), BackgroundColor3 = Color3.new(0, 0, 0), BackgroundTransparency = 0.3, TextColor3 = Color3.new(1, 1, 1), Text = "", TextSize = 13, Font = Enum.Font.GothamBold, Visible = false, ZIndex = 11, }, screenGui) roundify(toastLabel, 8) local toastId = 0 local function toast(msg) toastId += 1 local id = toastId toastLabel.Text = msg toastLabel.Visible = true task.delay(1.8, function() if id == toastId and toastLabel.Parent then toastLabel.Visible = false end end) end -- Joysticks táteis local function makeStick(pos, caption, callback) local base = make("Frame", { Size = UDim2.new(0, 100, 0, 100), AnchorPoint = Vector2.new(0.5, 0.5), Position = pos, BackgroundColor3 = Color3.fromRGB(20, 20, 25), BackgroundTransparency = 0.5, BorderSizePixel = 0, Active = true, }, screenGui) roundify(base, 50) make("TextLabel", { Size = UDim2.new(1, 0, 0, 14), Position = UDim2.new(0, 0, 0, -16), BackgroundTransparency = 1, Text = caption, TextColor3 = Color3.new(1, 1, 1), TextSize = 10, Font = Enum.Font.GothamBold, }, base) local knob = make("Frame", { Size = UDim2.new(0, 40, 0, 40), AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), BackgroundColor3 = Color3.fromRGB(230, 230, 235), BackgroundTransparency = 0.2, BorderSizePixel = 0, }, base) roundify(knob, 20) local active local function update(p) local center = base.AbsolutePosition + base.AbsoluteSize / 2 local maxR = base.AbsoluteSize.X / 2 - 8 local delta = Vector2.new(p.X, p.Y) - center if delta.Magnitude > maxR then delta = delta.Unit * maxR end knob.Position = UDim2.new(0.5, delta.X, 0.5, delta.Y) callback(Vector2.new(delta.X / maxR, -delta.Y / maxR)) end local function reset() active = nil knob.Position = UDim2.new(0.5, 0, 0.5, 0) callback(Vector2.zero) end base.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then active = input update(input.Position) end end) table.insert(conns, UserInputService.InputChanged:Connect(function(input) if not active then return end if input == active or (active.UserInputType == Enum.UserInputType.MouseButton1 and input.UserInputType == Enum.UserInputType.MouseMovement) then update(input.Position) end end)) table.insert(conns, UserInputService.InputEnded:Connect(function(input) if input == active then reset() end end)) end makeStick(UDim2.new(0, 80, 1, -65), "ALTURA / GIRAR", function(v) stickL = v end) makeStick(UDim2.new(1, -80, 1, -65), "MOVER", function(v) stickR = v end) -- Arrastar o comando pela barra superior do local dragging, dragStart, startPos2 topBar.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = input dragStart = input.Position startPos2 = rcFrame.Position end end) table.insert(conns, UserInputService.InputChanged:Connect(function(input) if dragging and (input == dragging or (dragging.UserInputType == Enum.UserInputType.MouseButton1 and input.UserInputType == Enum.UserInputType.MouseMovement)) then local d = input.Position - dragStart rcFrame.Position = UDim2.new(startPos2.X.Scale, startPos2.X.Offset + d.X, startPos2.Y.Scale, startPos2.Y.Offset + d.Y) end end)) table.insert(conns, UserInputService.InputEnded:Connect(function(input) if input == dragging then dragging = nil end end)) end --------------------------------------------------------------------- -- 3. Lógica --------------------------------------------------------------------- local function cleanup() for _, c in ipairs(conns) do pcall(function() c:Disconnect() end) end table.clear(conns) pcall(function() camera.CameraType = Enum.CameraType.Custom camera.FieldOfView = DEFAULT_FOV local hum = getHumanoid() if hum then camera.CameraSubject = hum end end) colorCorrection.Parent = nil if droneModel then droneModel:Destroy() end if screenGui then screenGui:Destroy() end env.__DroneCleanup = nil end env.__DroneCleanup = cleanup local function refreshFlyBtn() btns.fly.Text = flying and "🛬 Pousar" or "🚀 Voar" setBtn(btns.fly, flying) end local function setMode(m) mode = m setBtn(btns.rth, m == "rth") setBtn(btns.follow, m == "follow") end local function homePos() return rootPart.Position + rootPart.CFrame.LookVector * 5 + Vector3.new(0, 8, 0) end local function followPos() return rootPart.Position - rootPart.CFrame.LookVector * 6 + Vector3.new(0, 5, 0) end local function faceDir(v, dt) if v.Magnitude < 0.1 then return end local target = math.atan2(-v.X, -v.Z) local diff = (target - yaw + math.pi) % (2 * math.pi) - math.pi yaw = yaw + diff * math.min(1, dt * 4) end local function takePhoto() flash.BackgroundTransparency = 0.1 TweenService:Create(flash, TweenInfo.new(0.4), {BackgroundTransparency = 1}):Play() toast("📸 Foto guardada") end -- Botões de Ação btns.fly.MouseButton1Click:Connect(function() if flying then if mode ~= "land" then setMode("land") end else if battery < 5 then toast("🔋 Bateria demasiado baixa") return end flying = true setMode("takeoff") refreshFlyBtn() end end) btns.cam.MouseButton1Click:Connect(function() cameraAttached = not cameraAttached hudGui.Visible = cameraAttached setBtn(btns.cam, cameraAttached) btns.cam.Text = cameraAttached and "👤 Jogador" or "👁️ Câmara" if cameraAttached then camera.CameraType = Enum.CameraType.Scriptable else camera.CameraType = Enum.CameraType.Custom camera.FieldOfView = DEFAULT_FOV local hum = getHumanoid() if hum then camera.CameraSubject = hum end end end) btns.rth.MouseButton1Click:Connect(function() if not flying then toast("O drone está no chão") return end setMode(mode == "rth" and "manual" or "rth") end) btns.follow.MouseButton1Click:Connect(function() if not flying then toast("O drone está no chão") return end setMode(mode == "follow" and "manual" or "follow") end) btns.zin.MouseButton1Click:Connect(function() fov = math.max(20, fov - 10) end) btns.zout.MouseButton1Click:Connect(function() fov = math.min(100, fov + 10) end) btns.photo.MouseButton1Click:Connect(takePhoto) btns.rec.MouseButton1Click:Connect(function() recording = not recording if recording then recTime = 0 end btns.rec.Text = recording and "⏹ Parar" or "🔴 REC" setBtn(btns.rec, recording) toast(recording and "🔴 A gravar" or "⏹ Gravação guardada") end) btns.light.MouseButton1Click:Connect(function() lightOn = not lightOn light.Enabled = lightOn lightPart.Material = lightOn and Enum.Material.Neon or Enum.Material.SmoothPlastic setBtn(btns.light, lightOn) end) btns.color.MouseButton1Click:Connect(function() lightIdx = lightIdx % #lightColors + 1 lightPart.Color = lightColors[lightIdx] light.Color = lightColors[lightIdx] btns.color.BackgroundColor3 = lightColors[lightIdx]:Lerp(Color3.new(0, 0, 0), 0.5) end) -- Nova Função: Térmico btns.thermal.MouseButton1Click:Connect(function() thermalOn = not thermalOn setBtn(btns.thermal, thermalOn) if thermalOn then colorCorrection.TintColor = Color3.fromRGB(255, 120, 50) colorCorrection.Contrast = 0.5 colorCorrection.Brightness = 0.1 colorCorrection.Parent = Lighting toast("🌡️ Visão térmica ativa") else colorCorrection.Parent = nil toast("🌡️ Visão normal") end end) -- Nova Função: Largar Bomba btns.drop.MouseButton1Click:Connect(function() if not flying then toast("O drone precisa de estar a voar") return end local bomb = Instance.new("Part") bomb.Size = Vector3.new(0.8, 0.8, 0.8) bomb.Position = dronePart.Position - Vector3.new(0, 1, 0) bomb.Material = Enum.Material.Neon bomb.Color = Color3.fromRGB(255, 50, 50) bomb.Shape = Enum.PartType.Ball bomb.Parent = Workspace local touchedConn touchedConn = bomb.Touched:Connect(function(hit) if hit ~= dronePart and hit.Parent ~= droneModel then touchedConn:Disconnect() local exp = Instance.new("Explosion") exp.Position = bomb.Position exp.BlastRadius = 8 exp.BlastPressure = 10000 exp.Parent = Workspace bomb:Destroy() end end) toast("📦 Carga largada!") end) btns.pull.MouseButton1Click:Connect(function() local target = rootPart.Position + rootPart.CFrame.LookVector * 4 local y if flying then y = target.Y + 4 else local gy = groundY(target + Vector3.new(0, 5, 0)) y = (gy or (target.Y - 2.5)) + 0.9 end dronePart.CFrame = CFrame.new(target.X, y, target.Z) * CFrame.Angles(0, yaw, 0) curVel = Vector3.zero end) btns.boom.MouseButton1Click:Connect(function() if dronePart and dronePart.Parent then local explosion = Instance.new("Explosion") explosion.Position = dronePart.Position explosion.BlastRadius = 18 explosion.BlastPressure = 500000 explosion.Parent = Workspace cleanup() end end) btnClose.MouseButton1Click:Connect(cleanup) table.insert(conns, player.CharacterAdded:Connect(function(c) character = c rootPart = c:WaitForChild("HumanoidRootPart") rayParams.FilterDescendantsInstances = {droneModel, c} end)) local function getInput() return stickL.X, stickL.Y, stickR.X, stickR.Y end local modeNames = { manual = "MANUAL", takeoff = "A DESCOLAR", rth = "REGRESSAR A CASA", follow = "A SEGUIR-TE", land = "A ATERRAR", } local uiTimer = 0 -- Ciclo principal table.insert(conns, RunService.RenderStepped:Connect(function(dt) if not dronePart.Parent then cleanup() return end local pos = dronePart.Position local gy = groundY(pos) local minY = gy and (gy + 0.9) or -math.huge local yawIn, vertIn, strafeIn, fwdIn = getInput() local inputMag = math.abs(yawIn) + math.abs(vertIn) + math.abs(strafeIn) + math.abs(fwdIn) local vel = Vector3.zero local tiltF, tiltS = 0, 0 if flying then battery = math.max(0, battery - dt * (0.5 + curVel.Magnitude / 80)) if battery <= 0 and mode ~= "land" then setMode("land") toast("🔋 Bateria vazia, a aterrar") end if inputMag > 0.2 and battery > 0 and (mode == "rth" or mode == "follow" or mode == "land") then setMode("manual") end if mode == "takeoff" then vel = Vector3.new(0, 8, 0) if pos.Y - (gy or (pos.Y - 3)) >= 3 then setMode("manual") end elseif mode == "manual" then yaw = yaw - yawIn * dt * YAW_SPEED local horiz = CFrame.Angles(0, yaw, 0):VectorToWorldSpace( Vector3.new(strafeIn * SPEED, 0, -fwdIn * SPEED)) vel = horiz + Vector3.new(0, vertIn * VSPEED, 0) tiltF, tiltS = fwdIn, strafeIn elseif mode == "rth" then local d = homePos() - pos local flat = Vector3.new(d.X, 0, d.Z) if flat.Magnitude > 3 then vel = flat.Unit * math.min(SPEED, flat.Magnitude * 3) + Vector3.new(0, math.clamp(d.Y * 2, -VSPEED, VSPEED), 0) faceDir(flat, dt) tiltF = 0.6 else setMode("land") end elseif mode == "follow" then local d = followPos() - pos vel = d * 3 if vel.Magnitude > SPEED * 1.1 then vel = vel.Unit * SPEED * 1.1 end local toPlayer = rootPart.Position - pos faceDir(Vector3.new(toPlayer.X, 0, toPlayer.Z), dt) elseif mode == "land" then vel = Vector3.new(0, -8, 0) if gy and pos.Y <= minY + 0.15 then flying = false setMode("manual") refreshFlyBtn() toast("🛬 Aterrou") end end if pos.Y <= minY and vel.Y < 0 then vel = Vector3.new(vel.X, 0, vel.Z) end else battery = math.min(100, battery + dt * 3) end curVel = curVel:Lerp(vel, math.min(1, dt * 5)) curTiltF = curTiltF + (tiltF - curTiltF) * math.min(1, dt * 6) curTiltS = curTiltS + (tiltS - curTiltS) * math.min(1, dt * 6) bv.Velocity = curVel bg.CFrame = CFrame.Angles(0, yaw, 0) * CFrame.Angles(-curTiltF * 0.3, 0, -curTiltS * 0.3) local targetRotor = flying and (45 + curVel.Magnitude * 0.5) or 0 rotorSpeed = rotorSpeed + (targetRotor - rotorSpeed) * math.min(1, dt * 3) rotorAngle = rotorAngle + rotorSpeed * dt for _, r in ipairs(rotors) do r.weld.C0 = r.base * CFrame.Angles(0, rotorAngle * r.dir, 0) end if cameraAttached then local gp = dronePart.CFrame:PointToWorldSpace(Vector3.new(0, -0.2, -1.7)) camera.CFrame = CFrame.new(gp) * CFrame.Angles(0, yaw, 0) camera.FieldOfView = fov end if recording then recTime += dt end uiTimer += dt if uiTimer >= 0.1 then uiTimer = 0 local alt = gy and (pos.Y - gy) or pos.Y local dist = (pos - rootPart.Position).Magnitude local zoomX = DEFAULT_FOV / fov local bat = math.floor(battery) local telemetry = string.format("ALT %dm VEL %d DIST %dm\n🔋 %d%% 🔍 x%.1f", math.floor(alt), math.floor(curVel.Magnitude), math.floor(dist), bat, zoomX) local state = flying and modeNames[mode] or (battery < 100 and "A CARREGAR" or "NO CHÃO") screenLabel.Text = "📡 " .. state .. "\n" .. telemetry hudTelemetry.Text = telemetry local bc = battery > 50 and Color3.fromRGB(0, 255, 120) or battery > 20 and Color3.fromRGB(255, 200, 0) or Color3.fromRGB(255, 60, 60) ledStatus.TextColor3 = bc ledStatus.Text = string.format("🔋 %d%% [ DJI RC - LINKED ]", bat) if recording then local blink = math.floor(recTime * 2) % 2 == 0 hudRec.Text = string.format("[ %s REC %02d:%02d ]", blink and "🔴" or "⚫", math.floor(recTime / 60), math.floor(recTime % 60)) else hudRec.Text = "[ ⏺ STANDBY ]" end end end)) print("Drone DJI RC v3 (com Térmico e Bombas) carregado com sucesso!")