
Key RequiredUniversal

-- =========================================================
-- ULTIMATE TORNADO ENGINE V6 (DYNAMIC PHYSICS DROPDOWN)
-- =========================================================
local RunService = game:GetService("RunService")
local PathfindingService = game:GetService("PathfindingService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
-- System Variables
local TornadoActive = false
local TornadoModel = nil
local FunnelSegments = {}
local CurrentPath = {}
local CurrentWaypoint = 1
-- CUSTOMIZATION SETTINGS (10+ Options)
local Settings = {
EF_Level = 1,
WanderSpeed = 25,
PhysicsMode = "Original", -- NEW MODE TOGGLE
PullStrengthMult = 1.0,
RadiusMult = 1.0,
LiftSpeed = 1.0,
RotationSpeed = 1.0,
DebrisDensity = 100,
FunnelTrans = 0.6,
Color_R = 100,
Color_G = 100,
Color_B = 105,
}
local EF_STATS = {
[1] = {Radius = 60, Strength = 40, Height = 150, Scale = 1},
[2] = {Radius = 100, Strength = 70, Height = 220, Scale = 1.6},
[3] = {Radius = 160, Strength = 120, Height = 320, Scale = 2.4},
[4] = {Radius = 240, Strength = 200, Height = 450, Scale = 3.5},
[5] = {Radius = 350, Strength = 320, Height = 600, Scale = 5.0}
}
-- =========================================================
-- 1. ADVANCED TABBED GUI SYSTEM
-- =========================================================
local ScreenGui = Instance.new("ScreenGui", Player:WaitForChild("PlayerGui"))
ScreenGui.Name = "StormOS"
ScreenGui.ResetOnSpawn = false
local MainFrame = Instance.new("Frame", ScreenGui)
MainFrame.Size, MainFrame.Position = UDim2.new(0, 360, 0, 480), UDim2.new(1, -380, 0.5, -240)
MainFrame.BackgroundColor3 = Color3.fromRGB(15, 15, 18)
MainFrame.Active = true
Instance.new("UICorner", MainFrame).CornerRadius = UDim.new(0, 12)
Instance.new("UIStroke", MainFrame).Color = Color3.fromRGB(80, 140, 255)
-- Draggable Logic
local dragging, dragInput, dragStart, startPos
MainFrame.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
dragging = true dragStart = input.Position startPos = MainFrame.Position
input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end)
end
end)
MainFrame.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then dragInput = input end
end)
UserInputService.InputChanged:Connect(function(input)
if input == dragInput and dragging then
local delta = input.Position - dragStart
MainFrame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
end
end)
local Title = Instance.new("TextLabel", MainFrame)
Title.Size, Title.Text = UDim2.new(1, 0, 0, 40), "STORM OS v6.0"
Title.Font, Title.TextColor3, Title.TextSize = Enum.Font.GothamBlack, Color3.new(1,1,1), 16
Title.BackgroundTransparency = 1
-- Tabs
local TabContainer = Instance.new("Frame", MainFrame)
TabContainer.Size, TabContainer.Position = UDim2.new(1, -20, 0, 35), UDim2.new(0, 10, 0, 40)
TabContainer.BackgroundTransparency = 1
local TabLayout = Instance.new("UIListLayout", TabContainer)
TabLayout.FillDirection, TabLayout.Padding = Enum.FillDirection.Horizontal, UDim.new(0, 5)
local ContentArea = Instance.new("Frame", MainFrame)
ContentArea.Size, ContentArea.Position = UDim2.new(1, -20, 1, -95), UDim2.new(0, 10, 0, 85)
ContentArea.BackgroundColor3 = Color3.fromRGB(22, 22, 26)
Instance.new("UICorner", ContentArea)
local Tabs = {}
local function CreateTab(name)
local btn = Instance.new("TextButton", TabContainer)
btn.Size, btn.Text, btn.BackgroundColor3 = UDim2.new(0.31, 0, 1, 0), name, Color3.fromRGB(30, 30, 35)
btn.TextColor3, btn.Font, btn.TextSize = Color3.new(0.7,0.7,0.7), Enum.Font.GothamBold, 12
Instance.new("UICorner", btn)
local frame = Instance.new("ScrollingFrame", ContentArea)
frame.Size, frame.BackgroundTransparency = UDim2.new(1, -10, 1, -10), 1
frame.Position = UDim2.new(0, 5, 0, 5)
frame.ScrollBarThickness, frame.Visible = 2, false
local layout = Instance.new("UIListLayout", frame)
layout.Padding, layout.HorizontalAlignment = UDim.new(0, 8), Enum.HorizontalAlignment.Center
btn.MouseButton1Click:Connect(function()
for _, t in pairs(Tabs) do t.Btn.BackgroundColor3 = Color3.fromRGB(30,30,35) t.Btn.TextColor3 = Color3.new(0.7,0.7,0.7) t.Frame.Visible = false end
btn.BackgroundColor3 = Color3.fromRGB(80, 140, 255)
btn.TextColor3 = Color3.new(1,1,1)
frame.Visible = true
end)
table.insert(Tabs, {Btn = btn, Frame = frame})
return frame
end
local TabControl = CreateTab("CONTROL")
local TabPhysics = CreateTab("PHYSICS")
local TabVisuals = CreateTab("VISUALS")
Tabs[1].Btn.BackgroundColor3 = Color3.fromRGB(80, 140, 255)
Tabs[1].Btn.TextColor3 = Color3.new(1,1,1)
TabControl.Visible = true
-- Helper to make setting rows
local function CreateSetting(parent, text, settingKey, min, max, step)
local row = Instance.new("Frame", parent)
row.Size, row.BackgroundTransparency = UDim2.new(1, 0, 0, 35), 1
local lbl = Instance.new("TextLabel", row)
lbl.Size, lbl.Text, lbl.TextColor3 = UDim2.new(0.6, 0, 1, 0), text, Color3.new(0.9,0.9,0.9)
lbl.BackgroundTransparency, lbl.Font, lbl.TextXAlignment = 1, Enum.Font.Gotham, Enum.TextXAlignment.Left
local valLbl = Instance.new("TextLabel", row)
valLbl.Size, valLbl.Position, valLbl.Text = UDim2.new(0.2, 0, 1, 0), UDim2.new(0.6, 0, 0, 0), tostring(Settings[settingKey])
valLbl.BackgroundTransparency, valLbl.TextColor3, valLbl.Font = 1, Color3.fromRGB(80, 140, 255), Enum.Font.GothamBold
local minus = Instance.new("TextButton", row)
minus.Size, minus.Position, minus.Text, minus.BackgroundColor3 = UDim2.new(0, 25, 0, 25), UDim2.new(0.8, 0, 0.5, -12), "-", Color3.fromRGB(40,40,45)
minus.TextColor3, minus.Font = Color3.new(1,1,1), Enum.Font.GothamBold
Instance.new("UICorner", minus)
local plus = Instance.new("TextButton", row)
plus.Size, plus.Position, plus.Text, plus.BackgroundColor3 = UDim2.new(0, 25, 0, 25), UDim2.new(0.9, 0, 0.5, -12), "+", Color3.fromRGB(40,40,45)
plus.TextColor3, plus.Font = Color3.new(1,1,1), Enum.Font.GothamBold
Instance.new("UICorner", plus)
local function update(change)
Settings[settingKey] = math.clamp(Settings[settingKey] + change, min, max)
valLbl.Text = tostring(math.floor(Settings[settingKey]*10)/10)
if settingKey == "Color_R" or settingKey == "Color_G" or settingKey == "Color_B" or settingKey == "FunnelTrans" then
if TornadoModel then UpdateVisuals() end
end
end
minus.MouseButton1Click:Connect(function() update(-step) end)
plus.MouseButton1Click:Connect(function() update(step) end)
end
-- NEW DROPDOWN MENU CREATOR
local function CreateDropdown(parent, text, settingKey, options)
local row = Instance.new("Frame", parent)
row.Size, row.BackgroundTransparency = UDim2.new(1, 0, 0, 35), 1
row.ClipsDescendants = false
local lbl = Instance.new("TextLabel", row)
lbl.Size, lbl.Text, lbl.TextColor3 = UDim2.new(0.5, 0, 1, 0), text, Color3.new(0.9,0.9,0.9)
lbl.BackgroundTransparency, lbl.Font, lbl.TextXAlignment = 1, Enum.Font.Gotham, Enum.TextXAlignment.Left
local dropBtn = Instance.new("TextButton", row)
dropBtn.Size, dropBtn.Position, dropBtn.Text = UDim2.new(0.5, 0, 0.8, 0), UDim2.new(0.5, 0, 0.1, 0), Settings[settingKey]
dropBtn.BackgroundColor3, dropBtn.TextColor3 = Color3.fromRGB(40, 40, 45), Color3.new(1,1,1)
dropBtn.Font = Enum.Font.GothamBold
Instance.new("UICorner", dropBtn)
-- Dropdown behavior (Cycles options on click to prevent clipping issues in scrolling frames)
local currentIndex = 1
dropBtn.MouseButton1Click:Connect(function()
currentIndex = currentIndex + 1
if currentIndex > #options then currentIndex = 1 end
Settings[settingKey] = options[currentIndex]
dropBtn.Text = options[currentIndex]
-- Visual flair when changed
dropBtn.BackgroundColor3 = Color3.fromRGB(80, 140, 255)
task.wait(0.1)
dropBtn.BackgroundColor3 = Color3.fromRGB(40, 40, 45)
end)
end
local function CreateActionBtn(parent, text, color, callback)
local b = Instance.new("TextButton", parent)
b.Size, b.BackgroundColor3, b.Text = UDim2.new(1, 0, 0, 45), color, text
b.Font, b.TextColor3, b.TextSize = Enum.Font.GothamBold, Color3.new(1,1,1), 14
Instance.new("UICorner", b)
b.MouseButton1Click:Connect(callback)
end
-- Populate UI
CreateActionBtn(TabControl, "SPAWN TORNADO", Color3.fromRGB(40, 180, 80), function() GenerateTornado() end)
CreateActionBtn(TabControl, "DESPAWN TORNADO", Color3.fromRGB(180, 50, 50), function() DestroyTornado() end)
CreateSetting(TabControl, "EF Intensity Scale", "EF_Level", 1, 5, 1)
CreateSetting(TabControl, "Wander AI Speed", "WanderSpeed", 0, 100, 5)
-- DROPDOWN MENU ADDED HERE
CreateDropdown(TabPhysics, "Vortex Mode", "PhysicsMode", {"Original", "Better"})
CreateSetting(TabPhysics, "Pull Radius Mult", "RadiusMult", 0.5, 3.0, 0.1)
CreateSetting(TabPhysics, "Suck Strength Mult", "PullStrengthMult", 0.5, 5.0, 0.1)
CreateSetting(TabPhysics, "Updraft Lift Speed", "LiftSpeed", 0.5, 3.0, 0.1)
CreateSetting(TabPhysics, "Rotation Speed Mult", "RotationSpeed", 0.1, 5.0, 0.2)
CreateSetting(TabVisuals, "Transparency", "FunnelTrans", 0.1, 1.0, 0.1)
CreateSetting(TabVisuals, "Debris Amount", "DebrisDensity", 0, 500, 50)
CreateSetting(TabVisuals, "Color: Red", "Color_R", 0, 255, 15)
CreateSetting(TabVisuals, "Color: Green", "Color_G", 0, 255, 15)
CreateSetting(TabVisuals, "Color: Blue", "Color_B", 0, 255, 15)
-- =========================================================
-- 2. TORNADO GENERATION & VISUALS
-- =========================================================
local DebrisEmitter = nil
function UpdateVisuals()
local col = Color3.fromRGB(Settings.Color_R, Settings.Color_G, Settings.Color_B)
for _, data in ipairs(FunnelSegments) do
data.Part.Color = col
data.Part.Transparency = Settings.FunnelTrans
end
if DebrisEmitter then
DebrisEmitter.Rate = Settings.DebrisDensity
DebrisEmitter.Color = ColorSequence.new(col)
end
end
function GenerateTornado()
if TornadoActive then return end
TornadoActive = true
TornadoModel = Instance.new("Model", workspace)
local Core = Instance.new("Part", TornadoModel)
Core.Anchored, Core.CanCollide, Core.Transparency = true, false, 1
Core.Position = Vector3.new(0, 5, 0)
TornadoModel.PrimaryPart = Core
local attach = Instance.new("Attachment", Core)
DebrisEmitter = Instance.new("ParticleEmitter", attach)
DebrisEmitter.Texture = "rbxassetid://258128463"
DebrisEmitter.Size = NumberSequence.new({NumberSequenceKeypoint.new(0, 20), NumberSequenceKeypoint.new(1, 100)})
DebrisEmitter.Transparency = NumberSequence.new(0.5, 1)
DebrisEmitter.Speed = NumberRange.new(50, 150)
DebrisEmitter.Lifetime = NumberRange.new(2, 4)
DebrisEmitter.SpreadAngle = Vector2.new(180, 180)
local stats = EF_STATS[Settings.EF_Level]
local segments = 20 + (Settings.EF_Level * 5)
task.spawn(function()
for i = 1, segments do
local p = Instance.new("Part")
p.Shape, p.Anchored = Enum.PartType.Cylinder, true
p.CanCollide, p.CanTouch, p.CanQuery = false, false, false
p.Material = Enum.Material.SmoothPlastic
local ratio = i / segments
local width = (5 + (ratio ^ 3) * (120 * stats.Scale))
p.Size = Vector3.new((stats.Height/segments) * 1.5, width, width)
local decal = Instance.new("Decal", p)
decal.Texture = "rbxassetid://258128463"
decal.Transparency = 0.5
p.Parent = TornadoModel
table.insert(FunnelSegments, {Part = p, Height = i * (stats.Height/segments), Speed = 15 * (1.2 - ratio)})
if i % 5 == 0 then task.wait() end
end
UpdateVisuals()
end)
task.spawn(function()
while TornadoActive do
local target = Core.Position + Vector3.new(math.random(-300, 300), 0, math.random(-300, 300))
local path = PathfindingService:CreatePath({AgentRadius = 10, AgentCanJump = false})
path:ComputeAsync(Core.Position, target)
if path.Status == Enum.PathStatus.Success then
CurrentPath = path:GetWaypoints()
CurrentWaypoint = 1
end
task.wait(math.random(6, 12))
end
end)
end
function DestroyTornado()
TornadoActive = false
if TornadoModel then TornadoModel:Destroy() end
table.clear(FunnelSegments)
CurrentPath = {}
end
-- =========================================================
-- 3. DYNAMIC PHYSICS ENGINE
-- =========================================================
RunService.Heartbeat:Connect(function(dt)
if not TornadoActive or not TornadoModel or not TornadoModel.PrimaryPart then return end
local t = tick()
local stats = EF_STATS[Settings.EF_Level]
local rootPos = TornadoModel.PrimaryPart.Position
if #CurrentPath > 0 and CurrentWaypoint <= #CurrentPath then
local wp = CurrentPath[CurrentWaypoint].Position
local targetPos = Vector3.new(wp.X, rootPos.Y, wp.Z)
local diff = targetPos - rootPos
if diff.Magnitude < 5 then CurrentWaypoint += 1 else TornadoModel.PrimaryPart.Position = rootPos + (diff.Unit * Settings.WanderSpeed * dt) end
end
for _, data in ipairs(FunnelSegments) do
local rot = CFrame.Angles(0, t * data.Speed * Settings.RotationSpeed, 0)
local wobble = Vector3.new(math.sin(t*3 + data.Height)*3, 0, math.cos(t*3 + data.Height)*3)
data.Part.CFrame = CFrame.new(rootPos + Vector3.new(0, data.Height, 0) + wobble) * rot * CFrame.Angles(0, 0, math.rad(90))
end
local params = OverlapParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {TornadoModel, Player.Character}
local searchRadius = stats.Radius * Settings.RadiusMult
local partsInRadius = workspace:GetPartBoundsInRadius(rootPos, searchRadius, params)
for _, p in ipairs(partsInRadius) do
if p:IsA("BasePart") and not p.Anchored then
local offset = p.Position - rootPos
local currentHeight = p.Position.Y - rootPos.Y
local horizontalDist = Vector3.new(offset.X, 0, offset.Z).Magnitude
local forceMult = stats.Strength * Settings.PullStrengthMult
-- ===============================================
-- MODE 1: THE ORIGINAL (Geyser Spout)
-- ===============================================
if Settings.PhysicsMode == "Original" then
if currentHeight > (stats.Height * 0.95) then
p.AssemblyLinearVelocity = Vector3.new(math.random(-100, 100), 50, math.random(-100, 100)).Unit * (stats.Strength * 1.5)
continue
end
local tangent = Vector3.new(-offset.Z, 0, offset.X).Unit
local inward = -Vector3.new(offset.X, 0, offset.Z).Unit
local upward = Vector3.new(0, 1.8 * Settings.LiftSpeed, 0)
p.AssemblyLinearVelocity = (tangent * forceMult) + (inward * (forceMult * 0.4)) + (upward * forceMult)
-- ===============================================
-- MODE 2: THE BETTER (Dynamic Distance & Random Eject)
-- ===============================================
elseif Settings.PhysicsMode == "Better" then
-- Random Ejection: Parts can fly out anywhere if they are high enough
if currentHeight > (stats.Height * 0.3) and math.random(1, 150) == 1 then
local throwDir = Vector3.new(math.random(-100, 100), math.random(-20, 50), math.random(-100, 100)).Unit
p.AssemblyLinearVelocity = throwDir * (stats.Strength * math.random(1.5, 3))
continue
end
-- Distance Check
local distPercent = math.clamp(horizontalDist / searchRadius, 0, 1)
local liftPower = 1 - distPercent -- Closer = higher lift
if liftPower < 0.1 then liftPower = 0.1 end -- Prevent zero lift
local tangent = Vector3.new(-offset.Z, 0, offset.X).Unit
local inward = -Vector3.new(offset.X, 0, offset.Z).Unit
local upward = Vector3.new(0, 3 * Settings.LiftSpeed * liftPower, 0)
-- Stronger inward pull for farther parts, tighter spiral for closer parts
local suckForce = inward * (forceMult * (1.5 - distPercent))
p.AssemblyLinearVelocity = (tangent * forceMult) + suckForce + (upward * forceMult)
end
-- ===============================================
end
end
end)



This is actually FE
increible script y aparte libre, eres mi idolo
not fe
can you add an ability to control tornado?