-- ========================================================= -- 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)