local RunService = game:GetService("RunService") local PathfindingService = game:GetService("PathfindingService") local UserInputService = game:GetService("UserInputService") local Players = game:GetService("Players") local Player = Players.LocalPlayer local ActiveDisasterType = "Tornado" local ActiveStorms = {} local Settings = { SpawnPlacement = "Original", WanderSpeed = 25, Color_R = 100, Color_G = 100, Color_B = 105, FunnelTrans = 0.6, DebrisDensity = 100, DebrisVis = 0.8, EF_Level = 0, PhysicsMode = "Original", TornadoShape = "Classic", LiftSpeed = 1.0, RotationSpeed = 1.0, RadiusMult = 1.0, PullStrengthMult = 1.0, MobileButtonPosition = "Top-Right" } local EF_STATS = { [-1] = {Radius = 25, Strength = 15, Height = 70, Scale = 0.4}, [0] = {Radius = 40, Strength = 25, Height = 100, Scale = 0.6}, [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} } local ScreenGui = Instance.new("ScreenGui", Player:WaitForChild("PlayerGui")) ScreenGui.Name = "StormOS_V8_Merged" ScreenGui.ResetOnSpawn = false local ChangelogFrame = Instance.new("Frame", ScreenGui) ChangelogFrame.AnchorPoint = Vector2.new(0.5, 0.5) ChangelogFrame.Size = UDim2.new(0.45, 0, 0.5, 0) ChangelogFrame.Position = UDim2.new(0.5, 0, 0.5, 0) ChangelogFrame.BackgroundColor3 = Color3.fromRGB(15, 15, 18) ChangelogFrame.Visible = true Instance.new("UICorner", ChangelogFrame).CornerRadius = UDim.new(0, 12) Instance.new("UIStroke", ChangelogFrame).Color = Color3.fromRGB(80, 140, 255) local CL_Title = Instance.new("TextLabel", ChangelogFrame) CL_Title.Size = UDim2.new(1, 0, 0.1, 0) CL_Title.Text = "STORM OS v8.0 - CHANGELOG" CL_Title.Font = Enum.Font.GothamBlack CL_Title.TextColor3 = Color3.new(1, 1, 1) CL_Title.TextSize = 20 CL_Title.TextScaled = true CL_Title.BackgroundTransparency = 1 local CL_CloseBtn = Instance.new("TextButton", ChangelogFrame) CL_CloseBtn.Size = UDim2.new(0, 30, 0, 30) CL_CloseBtn.Position = UDim2.new(1, -35, 0, 5) CL_CloseBtn.Text = "X" CL_CloseBtn.BackgroundColor3 = Color3.fromRGB(180, 50, 50) CL_CloseBtn.TextColor3 = Color3.new(1, 1, 1) CL_CloseBtn.Font = Enum.Font.GothamBold CL_CloseBtn.TextScaled = true Instance.new("UICorner", CL_CloseBtn).CornerRadius = UDim.new(0, 6) local CL_Scroll = Instance.new("ScrollingFrame", ChangelogFrame) CL_Scroll.Size = UDim2.new(1, -20, 0.8, 0) CL_Scroll.Position = UDim2.new(0, 10, 0.15, 0) CL_Scroll.BackgroundColor3 = Color3.fromRGB(22, 22, 26) CL_Scroll.ScrollBarThickness = 3 CL_Scroll.CanvasSize = UDim2.new(0, 0, 0, 0) Instance.new("UICorner", CL_Scroll) local CL_Layout = Instance.new("UIListLayout", CL_Scroll) CL_Layout.Padding = UDim.new(0, 10) CL_Layout.HorizontalAlignment = Enum.HorizontalAlignment.Center CL_Layout.SortOrder = Enum.SortOrder.LayoutOrder local ChangelogEntries = { { Date = os.date("%Y-%m-%d %H:%M:%S"), Text = "Max 2 tornadoes – SPAWN creates first, SPAWN ADDITIONAL adds second. Mobile button positionable." }, { Date = "2026-05-24 18:30", Text = "Tornado physics improved – player & held tools excluded from pull." }, { Date = "2026-05-23 09:15", Text = "Initial V8 merge – tornado visual overhaul & responsive GUI." } } for i, entry in ipairs(ChangelogEntries) do local entryFrame = Instance.new("Frame", CL_Scroll) entryFrame.Size = UDim2.new(0.95, 0, 0, 45) entryFrame.BackgroundTransparency = 1 local dateLbl = Instance.new("TextLabel", entryFrame) dateLbl.Size = UDim2.new(1, 0, 0.35, 0) dateLbl.Text = "[" .. entry.Date .. "]" dateLbl.Font = Enum.Font.GothamBold dateLbl.TextColor3 = Color3.fromRGB(80, 140, 255) dateLbl.TextSize = 12 dateLbl.BackgroundTransparency = 1 dateLbl.TextXAlignment = Enum.TextXAlignment.Left local descLbl = Instance.new("TextLabel", entryFrame) descLbl.Size = UDim2.new(1, 0, 0.65, 0) descLbl.Position = UDim2.new(0, 0, 0.35, 0) descLbl.Text = entry.Text descLbl.Font = Enum.Font.Gotham descLbl.TextColor3 = Color3.new(0.9, 0.9, 0.9) descLbl.TextSize = 14 descLbl.BackgroundTransparency = 1 descLbl.TextXAlignment = Enum.TextXAlignment.Left descLbl.TextWrapped = true end local LoadingFrame = Instance.new("Frame", ScreenGui) LoadingFrame.Size = UDim2.new(1, 0, 1, 0) LoadingFrame.BackgroundColor3 = Color3.fromRGB(0, 0, 0) LoadingFrame.BackgroundTransparency = 0.3 LoadingFrame.Visible = false LoadingFrame.ZIndex = 10 local LoadingLabel = Instance.new("TextLabel", LoadingFrame) LoadingLabel.Size = UDim2.new(0.6, 0, 0.1, 0) LoadingLabel.AnchorPoint = Vector2.new(0.5, 0.5) LoadingLabel.Position = UDim2.new(0.5, 0, 0.4, 0) LoadingLabel.Text = "Loading StormOS v8.0..." LoadingLabel.Font = Enum.Font.GothamBlack LoadingLabel.TextColor3 = Color3.new(1, 1, 1) LoadingLabel.TextSize = 28 LoadingLabel.BackgroundTransparency = 1 LoadingLabel.TextScaled = true local ProgressBar = Instance.new("Frame", LoadingFrame) ProgressBar.Size = UDim2.new(0.4, 0, 0.03, 0) ProgressBar.AnchorPoint = Vector2.new(0.5, 0.5) ProgressBar.Position = UDim2.new(0.5, 0, 0.55, 0) ProgressBar.BackgroundColor3 = Color3.fromRGB(40, 40, 45) Instance.new("UICorner", ProgressBar) local ProgressFill = Instance.new("Frame", ProgressBar) ProgressFill.Size = UDim2.new(0, 0, 1, 0) ProgressFill.BackgroundColor3 = Color3.fromRGB(80, 140, 255) ProgressFill.BorderSizePixel = 0 Instance.new("UICorner", ProgressFill) local ProgressText = Instance.new("TextLabel", ProgressBar) ProgressText.Size = UDim2.new(1, 0, 1, 0) ProgressText.Text = "0%" ProgressText.Font = Enum.Font.GothamBold ProgressText.TextColor3 = Color3.new(1, 1, 1) ProgressText.TextSize = 14 ProgressText.BackgroundTransparency = 1 ProgressText.TextScaled = true local MainFrame = Instance.new("Frame", ScreenGui) MainFrame.AnchorPoint = Vector2.new(0.5, 0.5) MainFrame.Size = UDim2.new(0.35, 0, 0.6, 0) MainFrame.Position = UDim2.new(0.75, 0, 0.5, 0) MainFrame.BackgroundColor3 = Color3.fromRGB(15, 15, 18) MainFrame.Visible = false MainFrame.Active = true Instance.new("UICorner", MainFrame).CornerRadius = UDim.new(0, 12) Instance.new("UIStroke", MainFrame).Color = Color3.fromRGB(80, 140, 255) local dragging, dragStart, startPos MainFrame.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch 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) UserInputService.InputChanged:Connect(function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) 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 = UDim2.new(0.5, 0, 0.08, 0) Title.Text = "STORM OS v8.0" Title.Position = UDim2.new(0, 10, 0, 0) Title.Font = Enum.Font.GothamBlack Title.TextColor3 = Color3.new(1, 1, 1) Title.TextSize = 16 Title.TextScaled = true Title.BackgroundTransparency = 1 Title.TextXAlignment = Enum.TextXAlignment.Left local OpenBtn = Instance.new("TextButton", ScreenGui) OpenBtn.Size = UDim2.new(0, 50, 0, 50) OpenBtn.Text = "🌪️" OpenBtn.TextSize = 28 OpenBtn.BackgroundColor3 = Color3.fromRGB(20, 20, 25) OpenBtn.Visible = false Instance.new("UICorner", OpenBtn).CornerRadius = UDim.new(1, 0) Instance.new("UIStroke", OpenBtn).Color = Color3.fromRGB(80, 140, 255) local CloseBtn = Instance.new("TextButton", MainFrame) CloseBtn.Size = UDim2.new(0, 30, 0, 30) CloseBtn.Position = UDim2.new(1, -35, 0, 5) CloseBtn.Text = "X" CloseBtn.BackgroundColor3 = Color3.fromRGB(180, 50, 50) CloseBtn.TextColor3 = Color3.new(1, 1, 1) CloseBtn.Font = Enum.Font.GothamBold CloseBtn.TextScaled = true Instance.new("UICorner", CloseBtn).CornerRadius = UDim.new(0, 6) CloseBtn.MouseButton1Click:Connect(function() MainFrame.Visible = false OpenBtn.Visible = true end) OpenBtn.MouseButton1Click:Connect(function() MainFrame.Visible = true OpenBtn.Visible = false end) local ButtonPositions = { ["Top-Left"] = UDim2.new(0, 10, 0, 10), ["Top-Right"] = UDim2.new(1, -60, 0, 10), ["Bottom-Left"] = UDim2.new(0, 10, 1, -60), ["Bottom-Right"] = UDim2.new(1, -60, 1, -60), ["Center"] = UDim2.new(0.5, -25, 0.5, -25) } local function UpdateButtonPosition() local pos = ButtonPositions[Settings.MobileButtonPosition] if pos then OpenBtn.Position = pos end end UpdateButtonPosition() local TabContainer = Instance.new("Frame", MainFrame) TabContainer.Size = UDim2.new(1, -20, 0.07, 0) TabContainer.Position = UDim2.new(0, 10, 0.08, 0) TabContainer.BackgroundTransparency = 1 local TabLayout = Instance.new("UIListLayout", TabContainer) TabLayout.FillDirection = Enum.FillDirection.Horizontal TabLayout.Padding = UDim.new(0, 5) local ContentArea = Instance.new("Frame", MainFrame) ContentArea.Size = UDim2.new(1, -20, 0.8, 0) ContentArea.Position = UDim2.new(0, 10, 0.17, 0) 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 = UDim2.new(0.31, 0, 1, 0) btn.Text = name btn.BackgroundColor3 = Color3.fromRGB(30, 30, 35) btn.TextColor3 = Color3.new(0.7, 0.7, 0.7) btn.Font = Enum.Font.GothamBold btn.TextSize = 12 btn.TextScaled = true Instance.new("UICorner", btn) local frame = Instance.new("ScrollingFrame", ContentArea) frame.Size = UDim2.new(1, -10, 1, -10) frame.BackgroundTransparency = 1 frame.Position = UDim2.new(0, 5, 0, 5) frame.ScrollBarThickness = 2 frame.Visible = false frame.CanvasSize = UDim2.new(0, 0, 2, 0) local layout = Instance.new("UIListLayout", frame) layout.Padding = UDim.new(0, 8) layout.HorizontalAlignment = 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") local function CreateSetting(parent, text, settingKey, min, max, step) local row = Instance.new("Frame", parent) row.Size = UDim2.new(0.95, 0, 0, 35) row.BackgroundTransparency = 1 local lbl = Instance.new("TextLabel", row) lbl.Size = UDim2.new(0.5, 0, 1, 0) lbl.Text = text lbl.TextColor3 = Color3.new(0.9, 0.9, 0.9) lbl.BackgroundTransparency = 1 lbl.Font = Enum.Font.Gotham lbl.TextXAlignment = Enum.TextXAlignment.Left lbl.TextScaled = true local valLbl = Instance.new("TextLabel", row) valLbl.Size = UDim2.new(0.2, 0, 1, 0) valLbl.Position = UDim2.new(0.5, 0, 0, 0) valLbl.Text = tostring(Settings[settingKey]) valLbl.BackgroundTransparency = 1 valLbl.TextColor3 = Color3.fromRGB(80, 140, 255) valLbl.Font = Enum.Font.GothamBold valLbl.TextScaled = true local minus = Instance.new("TextButton", row) minus.Size = UDim2.new(0, 25, 0, 25) minus.Position = UDim2.new(0.75, 0, 0.5, -12) minus.Text = "-" minus.BackgroundColor3 = Color3.fromRGB(40, 40, 45) minus.TextColor3 = Color3.new(1, 1, 1) minus.Font = Enum.Font.GothamBold Instance.new("UICorner", minus) local plus = Instance.new("TextButton", row) plus.Size = UDim2.new(0, 25, 0, 25) plus.Position = UDim2.new(0.9, 0, 0.5, -12) plus.Text = "+" plus.BackgroundColor3 = Color3.fromRGB(40, 40, 45) plus.TextColor3 = Color3.new(1, 1, 1) plus.Font = 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" or settingKey == "DebrisVis" then UpdateVisuals() end end minus.MouseButton1Click:Connect(function() update(-step) end) plus.MouseButton1Click:Connect(function() update(step) end) end local function CreateDropdown(parent, text, settingKey, options) local row = Instance.new("Frame", parent) row.Size = UDim2.new(0.95, 0, 0, 35) row.BackgroundTransparency = 1 local lbl = Instance.new("TextLabel", row) lbl.Size = UDim2.new(0.5, 0, 1, 0) lbl.Text = text lbl.TextColor3 = Color3.new(0.9, 0.9, 0.9) lbl.BackgroundTransparency = 1 lbl.Font = Enum.Font.Gotham lbl.TextXAlignment = Enum.TextXAlignment.Left lbl.TextScaled = true local dropBtn = Instance.new("TextButton", row) dropBtn.Size = UDim2.new(0.45, 0, 0.8, 0) dropBtn.Position = UDim2.new(0.5, 0, 0.1, 0) dropBtn.Text = Settings[settingKey] dropBtn.BackgroundColor3 = Color3.fromRGB(40, 40, 45) dropBtn.TextColor3 = Color3.new(1, 1, 1) dropBtn.Font = Enum.Font.GothamBold dropBtn.TextScaled = true Instance.new("UICorner", dropBtn) local currentIndex = 1 for i, opt in ipairs(options) do if opt == Settings[settingKey] then currentIndex = i break end end dropBtn.MouseButton1Click:Connect(function() currentIndex = currentIndex + 1 if currentIndex > #options then currentIndex = 1 end Settings[settingKey] = options[currentIndex] dropBtn.Text = options[currentIndex] if settingKey == "MobileButtonPosition" then UpdateButtonPosition() end end) end local function CreateActionBtn(parent, text, color, callback) local b = Instance.new("TextButton", parent) b.Size = UDim2.new(0.95, 0, 0, 40) b.BackgroundColor3 = color b.Text = text b.Font = Enum.Font.GothamBold b.TextColor3 = Color3.new(1, 1, 1) b.TextSize = 14 b.TextScaled = true Instance.new("UICorner", b) b.MouseButton1Click:Connect(callback) return b end local function BuildUI_For_Disaster() TabControl:ClearAllChildren() TabPhysics:ClearAllChildren() TabVisuals:ClearAllChildren() Instance.new("UIListLayout", TabControl).Padding = UDim.new(0, 8) Instance.new("UIListLayout", TabPhysics).Padding = UDim.new(0, 8) Instance.new("UIListLayout", TabVisuals).Padding = UDim.new(0, 8) -- SPAWN TORNADO: only if none exist CreateActionBtn(TabControl, "SPAWN TORNADO", Color3.fromRGB(40, 180, 80), function() if #ActiveStorms == 0 then GenerateDisaster() end end) -- SPAWN ADDITIONAL: only if exactly 1 exists → total becomes 2 CreateActionBtn(TabControl, "SPAWN ADDITIONAL", Color3.fromRGB(150, 100, 40), function() if #ActiveStorms == 1 then GenerateDisaster() end end) CreateActionBtn(TabControl, "CLEAR ALL", Color3.fromRGB(180, 50, 50), function() DestroyDisaster() end) CreateDropdown(TabControl, "Spawn Placement", "SpawnPlacement", {"Original", "Infront"}) CreateSetting(TabControl, "Wander AI Speed", "WanderSpeed", 0, 100, 5) CreateSetting(TabControl, "EF Level (-1=EFU)", "EF_Level", -1, 5, 1) CreateDropdown(TabControl, "Tornado Shape", "TornadoShape", {"Classic", "Rope", "Wedge"}) 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, "Cloud Transp.", "FunnelTrans", 0.1, 1.0, 0.1) CreateSetting(TabVisuals, "Debris Visibility", "DebrisVis", 0.0, 1.0, 0.1) CreateSetting(TabVisuals, "Debris Density", "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) CreateDropdown(TabVisuals, "Mobile Button Pos", "MobileButtonPosition", {"Top-Left", "Top-Right", "Bottom-Left", "Bottom-Right", "Center"}) Tabs[1].Btn.BackgroundColor3 = Color3.fromRGB(80, 140, 255) Tabs[1].Btn.TextColor3 = Color3.new(1, 1, 1) TabControl.Visible = true end CL_CloseBtn.MouseButton1Click:Connect(function() ChangelogFrame.Visible = false LoadingFrame.Visible = true task.spawn(function() local duration = 20 local startTime = tick() while true do local elapsed = tick() - startTime local percent = math.min(100, math.floor((elapsed / duration) * 100)) ProgressFill.Size = UDim2.new(percent/100, 0, 1, 0) ProgressText.Text = percent .. "%" if elapsed >= duration then break end task.wait(0.1) end LoadingFrame.Visible = false BuildUI_For_Disaster() MainFrame.Visible = true OpenBtn.Visible = true UpdateButtonPosition() end) end) function UpdateVisuals() local col = Color3.fromRGB(Settings.Color_R, Settings.Color_G, Settings.Color_B) for _, stormData in ipairs(ActiveStorms) do if stormData.Emitter then stormData.Emitter.Rate = Settings.DebrisDensity stormData.Emitter.Color = ColorSequence.new(col) local t = math.clamp(1 - Settings.DebrisVis, 0, 1) stormData.Emitter.Transparency = NumberSequence.new({NumberSequenceKeypoint.new(0, t), NumberSequenceKeypoint.new(1, 1)}) end for _, data in ipairs(stormData.Segments) do if data.Part then data.Part.Color = col data.Part.Transparency = Settings.FunnelTrans end end end end local function isDescendantOfPlayerCharacter(part) local ancestor = part.Parent while ancestor do if ancestor:IsA("Model") and ancestor:FindFirstChild("Humanoid") then local player = Players:GetPlayerFromCharacter(ancestor) if player then return true end end ancestor = ancestor.Parent end return false end function GenerateDisaster() local StormID = tick() local DisasterModel = Instance.new("Model", workspace) DisasterModel.Name = "Tornado_" .. math.floor(StormID) local Core = Instance.new("Part", DisasterModel) Core.Anchored = true Core.CanCollide = false Core.Transparency = 1 if Settings.SpawnPlacement == "Infront" and Player.Character and Player.Character:FindFirstChild("HumanoidRootPart") then local rootPart = Player.Character.HumanoidRootPart Core.Position = rootPart.Position + (rootPart.CFrame.LookVector * 200) + Vector3.new(0, 5, 0) else Core.Position = Vector3.new(0, 5, 0) end DisasterModel.PrimaryPart = Core local attach = Instance.new("Attachment", Core) local StormData = { Model = DisasterModel, Core = Core, Emitter = nil, Segments = {}, Path = {}, Waypoint = 1, Active = true, NextScan = 0, CachedParts = {} } table.insert(ActiveStorms, StormData) task.spawn(function() local stats = EF_STATS[Settings.EF_Level] local segments = 20 + (Settings.EF_Level * 5) local DebrisEmitter = Instance.new("ParticleEmitter", attach) DebrisEmitter.Texture = "rbxassetid://258128463" DebrisEmitter.Size = NumberSequence.new({NumberSequenceKeypoint.new(0, 10), NumberSequenceKeypoint.new(1, 80)}) DebrisEmitter.Lifetime = NumberRange.new(3, 6) DebrisEmitter.Speed = NumberRange.new(20, 50) DebrisEmitter.SpreadAngle = Vector2.new(360, 360) DebrisEmitter.Drag = 2 DebrisEmitter.Acceleration = Vector3.new(0, 40, 0) DebrisEmitter.RotSpeed = NumberRange.new(-300, 300) DebrisEmitter.EmissionDirection = Enum.NormalId.Top StormData.Emitter = DebrisEmitter for i = 1, segments do local p = Instance.new("Part") p.Shape = Enum.PartType.Cylinder p.Anchored = true p.CanCollide = false local ratio = i / segments local width = (Settings.TornadoShape == "Rope" and (2 + (ratio ^ 3) * (40 * stats.Scale))) or (Settings.TornadoShape == "Wedge" and (20 + (ratio ^ 1.5) * (300 * stats.Scale))) or (5 + (ratio ^ 3) * (120 * stats.Scale)) p.Size = Vector3.new((stats.Height/segments) * 1.5, width, width) p.Parent = DisasterModel table.insert(StormData.Segments, {Part = p, Height = i * (stats.Height/segments), Speed = 15 * (1.2 - ratio), IsHurricane = false}) end UpdateVisuals() end) task.spawn(function() while StormData.Active do local target = Core.Position + Vector3.new(math.random(-500, 500), 0, math.random(-500, 500)) local path = PathfindingService:CreatePath({AgentRadius = 10}) path:ComputeAsync(Core.Position, target) if path.Status == Enum.PathStatus.Success then StormData.Path = path:GetWaypoints() StormData.Waypoint = 1 end task.wait(8) end end) end function DestroyDisaster() for _, storm in ipairs(ActiveStorms) do storm.Active = false if storm.Model then storm.Model:Destroy() end end table.clear(ActiveStorms) end RunService.Heartbeat:Connect(function(dt) local t = tick() for idx, Storm in ipairs(ActiveStorms) do if not Storm.Active or not Storm.Model.PrimaryPart then continue end local rootPos = Storm.Core.Position if #Storm.Path > 0 and Storm.Waypoint <= #Storm.Path then local targetPos = Vector3.new(Storm.Path[Storm.Waypoint].Position.X, rootPos.Y, Storm.Path[Storm.Waypoint].Position.Z) local diff = targetPos - rootPos if diff.Magnitude < 5 then Storm.Waypoint += 1 else Storm.Core.Position = rootPos + (diff.Unit * Settings.WanderSpeed * dt) end end for _, data in ipairs(Storm.Segments) do local rotAngle = t * data.Speed * Settings.RotationSpeed local wobbleX = math.sin(t * 2 + (data.Height * 0.05)) * (data.Height * 0.05) local wobbleZ = math.cos(t * 2 + (data.Height * 0.05)) * (data.Height * 0.05) data.Part.CFrame = CFrame.new(rootPos + Vector3.new(wobbleX, data.Height, wobbleZ)) * CFrame.Angles(0, rotAngle, 0) * CFrame.Angles(0, 0, math.rad(90)) end local stats = EF_STATS[Settings.EF_Level] local searchRadius = stats.Radius * Settings.RadiusMult if t >= Storm.NextScan then Storm.NextScan = t + 0.25 local parts = workspace:GetPartBoundsInRadius(rootPos, searchRadius) local validParts = {} for _, p in ipairs(parts) do if p:IsA("BasePart") and not p.Anchored and p.Size.Magnitude < 150 then if not isDescendantOfPlayerCharacter(p) then table.insert(validParts, p) end end end Storm.CachedParts = validParts end for _, p in ipairs(Storm.CachedParts) do if p and p.Parent then local offset = p.Position - rootPos local horizontalDist = Vector3.new(offset.X, 0, offset.Z).Magnitude local suctionForce = math.clamp(1 - (horizontalDist / searchRadius), 0, 1) local baseStrength = stats.Strength * Settings.PullStrengthMult local tangent = Vector3.new(-offset.Z, 0, offset.X).Unit local pull = -offset.Unit * (baseStrength * 0.5) local lift = Vector3.new(0, (baseStrength * 1.5) * Settings.LiftSpeed, 0) local spin = tangent * (baseStrength * 2.5) * Settings.RotationSpeed p.AssemblyLinearVelocity = (spin + lift + pull) * suctionForce end end end end)