writefile("WHATHAVEYOUDONE.mp3", game:HttpGet("https://github.com/ian49972/smth/raw/refs/heads/main/WHATHAVEYOUDONE.mp3")) local object = game:GetObjects("rbxassetid://10973669978")[1] object.Parent = game.Workspace object:PivotTo(game.Players.LocalPlayer.Character:GetPivot()) -------------------------------------------------- -- đŸ”ĩ WITHER STORM 10-SECOND FORMING -- -- 0–6 SECONDS: -- FULL BLUE -- -- 6–10 SECONDS: -- FLASH NORMAL ↔ BLUE -- -- BLUE OUTLINE: -- STAYS ON THE ENTIRE TIME -- -- STORM: -- FLOATS 8 STUDS ABOVE ORIGINAL POSITION -- -- TOP IMAGE: -- SNAPS ON IMMEDIATELY -- ONLY VISIBLE WITHIN 700 STUDS -- -- SOUND: -- PLAYS DURING FORMING -------------------------------------------------- local startupFinished = false local startupDuration = 10 local BLUE = Color3.fromRGB(0, 100, 255) local Players = game:GetService("Players") local RunService = game:GetService("RunService") local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") local character = player.Character or player.CharacterAdded:Wait() -------------------------------------------------- -- SAVE ORIGINAL COLORS -------------------------------------------------- local originalColors = {} for _, part in ipairs(object:GetDescendants()) do if part:IsA("BasePart") then originalColors[part] = part.Color end end -------------------------------------------------- -- SAVE ORIGINAL POSITION -------------------------------------------------- local originalPivot = object:GetPivot() local FORMING_HEIGHT = 8 local formingPivot = originalPivot * CFrame.new(0, FORMING_HEIGHT, 0) -------------------------------------------------- -- đŸ–ŧī¸ TOP IMAGE -- SNAPS ON AT 0 SECONDS -- VISIBLE ONLY WITHIN 700 STUDS -------------------------------------------------- local formingGui = Instance.new("ScreenGui") formingGui.Name = "WitherStormFormingTexture" formingGui.ResetOnSpawn = false formingGui.IgnoreGuiInset = true formingGui.Parent = playerGui local formingTexture = Instance.new("ImageLabel") formingTexture.Name = "FormingTopTexture" formingTexture.BackgroundTransparency = 1 formingTexture.Image = "rbxassetid://84433659224644" formingTexture.AnchorPoint = Vector2.new(0.5, 0) formingTexture.Position = UDim2.new(0.5, 0, 0, 0) formingTexture.Size = UDim2.new(1, 0, 0, 120) formingTexture.ScaleType = Enum.ScaleType.Fit -- ⚡ SNAP ON formingTexture.ImageTransparency = 0 formingTexture.Parent = formingGui -------------------------------------------------- -- 📏 TOP IMAGE 700-STUD DISTANCE CHECK -------------------------------------------------- local IMAGE_DISTANCE = 700 local imageDistanceConnection imageDistanceConnection = RunService.Heartbeat:Connect(function() if not formingTexture or not formingTexture.Parent then if imageDistanceConnection then imageDistanceConnection:Disconnect() end return end if not character or not character:FindFirstChild("HumanoidRootPart") or not object or not object.Parent then formingTexture.ImageTransparency = 1 return end local playerPos = character.HumanoidRootPart.Position local stormPos = object:GetPivot().Position local distance = (playerPos - stormPos).Magnitude -------------------------------------------------- -- WITHIN 700 STUDS -------------------------------------------------- if distance < IMAGE_DISTANCE then formingTexture.ImageTransparency = 0 -------------------------------------------------- -- 700+ STUDS -------------------------------------------------- else formingTexture.ImageTransparency = 1 end end) -------------------------------------------------- -- UPDATE CHARACTER AFTER RESPAWN -------------------------------------------------- player.CharacterAdded:Connect(function(newCharacter) character = newCharacter end) -------------------------------------------------- -- SET STORM COLOR -------------------------------------------------- local function setStormColor(color) if not object or not object.Parent then return end for _, part in ipairs(object:GetDescendants()) do if part:IsA("BasePart") then part.Color = color end end end -------------------------------------------------- -- RESTORE ORIGINAL COLORS -------------------------------------------------- local function restoreStormColors() if not object or not object.Parent then return end for part, color in pairs(originalColors) do if part and part.Parent then part.Color = color end end end -------------------------------------------------- -- đŸ”ĩ BLUE OUTLINE -------------------------------------------------- local stormOutline = Instance.new("Highlight") stormOutline.Name = "WitherStormStartupOutline" stormOutline.Adornee = object stormOutline.FillTransparency = 1 stormOutline.OutlineColor = BLUE stormOutline.OutlineTransparency = 0 stormOutline.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop stormOutline.Enabled = true stormOutline.Parent = object -------------------------------------------------- -- 🔊 EARLY FORMING SOUND -------------------------------------------------- local formingSound = Instance.new("Sound") formingSound.Name = "WitherStormFormingSound" formingSound.SoundId = "rbxassetid://89442225023445" formingSound.Volume = 2 formingSound.Looped = true formingSound.RollOffMode = Enum.RollOffMode.Linear formingSound.RollOffMinDistance = 50 formingSound.RollOffMaxDistance = 700 formingSound.Parent = workspace -------------------------------------------------- -- PLAY FORMING SOUND IMMEDIATELY -------------------------------------------------- formingSound:Play() -------------------------------------------------- -- đŸŒŠī¸ START FORMING -------------------------------------------------- object:PivotTo(formingPivot) task.spawn(function() local startTime = os.clock() -------------------------------------------------- -- đŸ”ĩ FIRST 6 SECONDS -- COMPLETELY BLUE -------------------------------------------------- setStormColor(BLUE) while os.clock() - startTime < 6 do if not object or not object.Parent then return end -------------------------------------------------- -- KEEP IMAGE DISTANCE SYSTEM RUNNING -------------------------------------------------- if formingTexture and formingTexture.Parent then -- Visibility is controlled by the -- 700-stud Heartbeat connection. end -------------------------------------------------- -- KEEP STORM FLOATING -------------------------------------------------- object:PivotTo(formingPivot) -------------------------------------------------- -- KEEP BLUE OUTLINE -------------------------------------------------- if stormOutline and stormOutline.Parent then stormOutline.Enabled = true end task.wait() end -------------------------------------------------- -- ⚡ LAST 4 SECONDS -- FLASH NORMAL ↔ BLUE -------------------------------------------------- local flashStart = os.clock() local blueMode = true while os.clock() - flashStart < 4 do if not object or not object.Parent then return end -------------------------------------------------- -- FLASH COLORS -------------------------------------------------- if blueMode then setStormColor(BLUE) else restoreStormColors() end -------------------------------------------------- -- KEEP STORM FLOATING -------------------------------------------------- object:PivotTo(formingPivot) -------------------------------------------------- -- BLUE OUTLINE STAYS ON -------------------------------------------------- if stormOutline and stormOutline.Parent then stormOutline.Enabled = true end blueMode = not blueMode task.wait(0.12) end -------------------------------------------------- -- FINISH IN NORMAL COLORS -------------------------------------------------- restoreStormColors() -------------------------------------------------- -- REMOVE BLUE OUTLINE -------------------------------------------------- if stormOutline and stormOutline.Parent then stormOutline:Destroy() end -------------------------------------------------- -- RETURN TO ORIGINAL HEIGHT -------------------------------------------------- if object and object.Parent then object:PivotTo(originalPivot) end -------------------------------------------------- -- STOP FORMING SOUND -------------------------------------------------- if formingSound and formingSound.Parent then formingSound:Stop() formingSound:Destroy() end -------------------------------------------------- -- 🌑 FADE TOP IMAGE OUT -- -- IMPORTANT: -- The 700-STUD SYSTEM still controls whether -- the image is allowed to be visible. -------------------------------------------------- if formingTexture and formingTexture.Parent then local fadeOutStart = os.clock() local fadeOutDuration = 0.5 while os.clock() - fadeOutStart < fadeOutDuration do if not formingTexture or not formingTexture.Parent then break end local alpha = math.clamp( (os.clock() - fadeOutStart) / fadeOutDuration, 0, 1 ) formingTexture.ImageTransparency = alpha task.wait() end if formingTexture and formingTexture.Parent then formingTexture.ImageTransparency = 1 end end -------------------------------------------------- -- REMOVE IMAGE DISTANCE CONNECTION -------------------------------------------------- if imageDistanceConnection then imageDistanceConnection:Disconnect() imageDistanceConnection = nil end -------------------------------------------------- -- REMOVE GUI -------------------------------------------------- if formingGui and formingGui.Parent then formingGui:Destroy() end -------------------------------------------------- -- START EVERYTHING BELOW -------------------------------------------------- startupFinished = true print("đŸŒŠī¸ WITHER STORM IS NOW ACTIVE") end) -------------------------------------------------- -- âŗ EVERYTHING BELOW WAITS FOR FORMING -------------------------------------------------- while not startupFinished do task.wait(0.05) end -------------------------------------------------- -- đŸ’Ĩ ONE-TIME WITHER STORM SPAWN EXPLOSION -------------------------------------------------- local explosionSound = Instance.new("Sound") explosionSound.SoundId = "rbxassetid://90854697257230" explosionSound.Volume = 3 explosionSound.Parent = workspace local explosion = Instance.new("Explosion") explosion.Position = object:GetPivot().Position explosion.BlastRadius = 25 explosion.BlastPressure = 0 explosion.DestroyJointRadiusPercent = 0 explosion.Parent = workspace explosionSound:Play() explosionSound.Ended:Connect(function() explosionSound:Destroy() end) local RunService = game:GetService("RunService") local Players = game:GetService("Players") local player = Players.LocalPlayer local character = player.Character or player.CharacterAdded:Wait() local currentPhase = 1 local partsSucked = 0 local attractedParts = {} -------------------------------------------------- -- đŸŒĢī¸ WITHER STORM SKY SYSTEM -- GRAY SKY NEAR STORM -- NORMAL SKY OUTSIDE RADIUS -------------------------------------------------- local Lighting = game:GetService("Lighting") local RunService = game:GetService("RunService") -------------------------------------------------- -- SAVE NORMAL SKY -------------------------------------------------- local normalSky = Lighting:FindFirstChildOfClass("Sky") if normalSky then normalSky = normalSky:Clone() normalSky.Name = "SavedNormalSky" end -------------------------------------------------- -- GRAY STORM SKY -------------------------------------------------- local stormSky = Instance.new("Sky") stormSky.Name = "WitherStormGraySky" local SKY_ID = "rbxassetid://13044392362" stormSky.SkyboxBk = SKY_ID stormSky.SkyboxDn = SKY_ID stormSky.SkyboxFt = SKY_ID stormSky.SkyboxLf = SKY_ID stormSky.SkyboxRt = SKY_ID stormSky.SkyboxUp = SKY_ID stormSky.Parent = nil -------------------------------------------------- -- RADIUS BY PHASE -------------------------------------------------- local skyRadiusByPhase = { [1] = 700, [1.5] = 700, [2] = 700, [2.5] = 700, [3] = 700, [3.5] = 700, [4] = 1300, [4.5] = 1600, [5] = 2200, [6] = 3000 } -------------------------------------------------- -- CURRENT SKY STATE -------------------------------------------------- local graySkyActive = false local function enableGraySky() if graySkyActive then return end graySkyActive = true -- Remove current sky local currentSky = Lighting:FindFirstChildOfClass("Sky") if currentSky then currentSky.Parent = nil end stormSky.Parent = Lighting end local function restoreNormalSky() if not graySkyActive then return end graySkyActive = false -- Remove gray sky if stormSky.Parent then stormSky.Parent = nil end -- Restore normal sky if normalSky then -- Remove any existing sky local currentSky = Lighting:FindFirstChildOfClass("Sky") if currentSky then currentSky:Destroy() end local restoredSky = normalSky:Clone() restoredSky.Name = "NormalSky" restoredSky.Parent = Lighting end end -------------------------------------------------- -- UPDATE -------------------------------------------------- RunService.Heartbeat:Connect(function() if not character or not character:FindFirstChild("HumanoidRootPart") or not object or not object.Parent then restoreNormalSky() return end local stormPosition = object:GetPivot().Position local playerPosition = character.HumanoidRootPart.Position local distance = (playerPosition - stormPosition).Magnitude local radius = skyRadiusByPhase[currentPhase] or 300 -------------------------------------------------- -- INSIDE RADIUS -------------------------------------------------- if distance <= radius then enableGraySky() -------------------------------------------------- -- OUTSIDE RADIUS -------------------------------------------------- else restoreNormalSky() end end) player.CharacterAdded:Connect(function(newChar) character = newChar end) -------------------------------------------------- -- 🔊 ONE-TIME SPAWN SOUNDS -------------------------------------------------- local spawnSound1 = Instance.new("Sound") spawnSound1.SoundId = "rbxassetid://120851527677912" spawnSound1.Volume = 2 spawnSound1.Parent = workspace local spawnSound2 = Instance.new("Sound") spawnSound2.SoundId = "rbxassetid://85950005322040" spawnSound2.Volume = 2 spawnSound2.Parent = workspace -- Play both once spawnSound1:Play() spawnSound2:Play() -- Clean them up after they finish spawnSound1.Ended:Connect(function() spawnSound1:Destroy() end) spawnSound2.Ended:Connect(function() spawnSound2:Destroy() end) -------------------------------------------------- -- đŸ–ŧī¸ TOP IMAGE DURING FORMING -- SNAPS IN IMMEDIATELY -------------------------------------------------- local Players = game:GetService("Players") local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") local formingGui = Instance.new("ScreenGui") formingGui.Name = "WitherStormFormingTexture" formingGui.ResetOnSpawn = false formingGui.IgnoreGuiInset = true formingGui.Parent = playerGui local formingTexture = Instance.new("ImageLabel") formingTexture.Name = "FormingTopTexture" formingTexture.BackgroundTransparency = 1 formingTexture.Image = "rbxassetid://84433659224644" formingTexture.AnchorPoint = Vector2.new(0.5, 0) formingTexture.Position = UDim2.new(0.5, 0, 0, 0) formingTexture.Size = UDim2.new(1, 0, 0, 120) formingTexture.ScaleType = Enum.ScaleType.Fit -------------------------------------------------- -- ⚡ SNAP IN -- NO FADE IN -------------------------------------------------- formingTexture.ImageTransparency = 0 formingTexture.Parent = formingGui -------------------------------------------------- -- 🔊 EARLY LOOPING SOUND -- PLAYS DURING FORMING + PHASE 1 TO 3.5 -------------------------------------------------- local earlyLoopSound = Instance.new("Sound") earlyLoopSound.Name = "EarlyPhaseLoopSound" earlyLoopSound.SoundId = "rbxassetid://89442225023445" earlyLoopSound.Volume = 2 earlyLoopSound.Looped = true earlyLoopSound.RollOffMode = Enum.RollOffMode.Linear earlyLoopSound.RollOffMinDistance = 50 earlyLoopSound.RollOffMaxDistance = 700 earlyLoopSound.Parent = workspace -------------------------------------------------- -- PHASE CHECK -------------------------------------------------- local function isEarlyLoopPhase() return currentPhase == 1 or currentPhase == 1.5 or currentPhase == 2 or currentPhase == 2.5 or currentPhase == 3 or currentPhase == 3.5 end -------------------------------------------------- -- đŸ”ĩ START SOUND IMMEDIATELY -- INCLUDING THE 5-SECOND FORMING -------------------------------------------------- earlyLoopSound:Play() -------------------------------------------------- -- 🔊 SOUND CONTROL -------------------------------------------------- RunService.Heartbeat:Connect(function() if not earlyLoopSound or not earlyLoopSound.Parent then return end -------------------------------------------------- -- DURING 5-SECOND FORMING -- SOUND STAYS ACTIVE -------------------------------------------------- if not startupFinished then if not earlyLoopSound.IsPlaying then earlyLoopSound:Play() end -------------------------------------------------- -- PHASE 1 → 3.5 -------------------------------------------------- elseif isEarlyLoopPhase() then if not earlyLoopSound.IsPlaying then earlyLoopSound:Play() end -------------------------------------------------- -- PHASE 4+ -- STOP COMPLETELY -------------------------------------------------- else earlyLoopSound.Volume = 0 if earlyLoopSound.IsPlaying then earlyLoopSound:Stop() end return end -------------------------------------------------- -- DISTANCE VOLUME -------------------------------------------------- if character and character:FindFirstChild("HumanoidRootPart") and object and object.Parent then local playerPos = character.HumanoidRootPart.Position local stormPos = object:GetPivot().Position local distance = (playerPos - stormPos).Magnitude if distance >= 700 then earlyLoopSound.Volume = 0 else local alpha = distance / 700 earlyLoopSound.Volume = 2 * (1 - alpha) end end end) -- Start immediately in Phase 1 earlyLoopSound:Play() local suctionRadiusByPhase = { [1] = 100, [1.5] = 150, [2] = 250, [2.5] = 350, [3] = 500, [3.5] = 700, [4] = 900, [4.5] = 1200, [5] = 1600, [6] = 2200 } local function getSuctionRadius() return suctionRadiusByPhase[currentPhase] or 100 end coroutine.wrap(function() while true do task.wait(0.5) if not object or not object.Parent then continue end local objectPos = object:GetPivot().Position local suctionRadius = getSuctionRadius() local candidates = {} for _, obj in ipairs(game.Workspace:GetDescendants()) do if obj:IsA("BasePart") and obj.Parent and not obj.Anchored and not isCharacterPart(obj) and not obj:IsDescendantOf(object) and obj.Size.Magnitude < 20 and not table.find(attractedParts, obj) then local dist = (obj.Position - objectPos).Magnitude if dist <= suctionRadius then table.insert(candidates, { obj = obj, dist = dist }) end end end if #candidates > 0 then table.sort(candidates, function(a, b) return a.dist < b.dist end) -- Grab several parts depending on the phase local maxGrab = math.clamp( math.floor(currentPhase * 2), 2, 12 ) for i = 1, math.min(maxGrab, #candidates) do local chosen = candidates[i].obj if chosen and chosen.Parent then chosen.Anchored = false table.insert(attractedParts, chosen) end end end end end)() local phaseModels = { [1] = "rbxassetid://10973669978", [1.5] = "rbxassetid://10682730940", [2] = "rbxassetid://10682788827", [2.5] = "rbxassetid://10980258642", [3] = "rbxassetid://10980269902", [3.5] = "rbxassetid://10980286260", [4] = "rbxassetid://111863453592689", [4.5] = "rbxassetid://16333160399", [5] = "rbxassetid://16333160399", [6] = "rbxassetid://16333261175" } local phasePartsSucked = { 0, -- Phase 1 5, -- Phase 1.5 40, -- Phase 2 55, -- Phase 2.5 120, -- Phase 3 200, -- Phase 3.5 270, -- Phase 4 850, -- Phase 4.5 1000, -- Phase 5 6200 -- Phase 6 } local function isCharacterPart(part) local model = part:FindFirstAncestorWhichIsA("Model") return model and model:FindFirstChildWhichIsA("Humanoid") ~= nil end local function disableCollisions(model) for _, part in ipairs(model:GetDescendants()) do if part:IsA("BasePart") then part.CanCollide = false end end end local function changePhase(newPhase) if currentPhase == newPhase then return end local oldPosition = object:GetPivot() object:Destroy() object = game:GetObjects(phaseModels[newPhase])[1] object.Parent = game.Workspace object:PivotTo(oldPosition) disableCollisions(object) currentPhase = newPhase print("Big boy") end local function onPartDestroyed() partsSucked = partsSucked + 1 for phase, threshold in pairs({ [1] = 0, [1.5] = 5, [2] = 40, [2.5] = 55, [3] = 120, [3.5] = 200, [4] = 270, [4.5] = 850, [5] = 1000, [6] = 6200 }) do if partsSucked >= threshold and phase > currentPhase then changePhase(phase) end end end coroutine.wrap(function() while true do task.wait(2) local candidates = {} for _, obj in ipairs(game.Workspace:GetDescendants()) do if obj:IsA("BasePart") and obj.Parent and not isCharacterPart(obj) and not obj:IsDescendantOf(object) and obj.Size.Magnitude < 20 and not table.find(attractedParts, obj) then local dist = (obj.Position - object:GetPivot().Position).Magnitude table.insert(candidates, {obj = obj, dist = dist}) end end if #candidates > 0 then table.sort(candidates, function(a, b) return a.dist < b.dist end) local chosen = candidates[1].obj if chosen.Anchored then chosen.Anchored = false end table.insert(attractedParts, chosen) end end end)() local shakingParts = {} local SHAKE_TIME = 1 local EAT_DISTANCE = 2 -------------------------------------------------- -- 🌑 SUCTION / SHAKE / BLACKENING SYSTEM -------------------------------------------------- local shakingParts = {} local PRE_SHAKE_TIME = 0.6 local SHAKE_STRENGTH = 0.45 local SHAKE_DISTANCE = 8 local EAT_DISTANCE = 2 local SHAKE_FREQUENCY = 18 local SUCTION_SPEED = 5 -------------------------------------------------- -- BLACKENING SETTINGS -------------------------------------------------- local BLACKEN_START_DISTANCE = 35 local BLACKEN_END_DISTANCE = 2 local function getBlackAlpha(distance) if distance >= BLACKEN_START_DISTANCE then return 0 end if distance <= BLACKEN_END_DISTANCE then return 1 end return 1 - ( (distance - BLACKEN_END_DISTANCE) / (BLACKEN_START_DISTANCE - BLACKEN_END_DISTANCE) ) end -------------------------------------------------- -- STORE ORIGINAL COLORS -------------------------------------------------- local function setupBlackening(part) if not part:GetAttribute("OriginalR") then local c = part.Color part:SetAttribute("OriginalR", c.R) part:SetAttribute("OriginalG", c.G) part:SetAttribute("OriginalB", c.B) end end -------------------------------------------------- -- SMOOTHLY TURN PART BLACK -------------------------------------------------- local function updateBlackening(part, distance) if not part or not part.Parent then return end setupBlackening(part) local originalColor = Color3.new( part:GetAttribute("OriginalR") or part.Color.R, part:GetAttribute("OriginalG") or part.Color.G, part:GetAttribute("OriginalB") or part.Color.B ) local alpha = getBlackAlpha(distance) part.Color = originalColor:Lerp( Color3.new(0, 0, 0), alpha ) end -------------------------------------------------- -- SMOOTH ROTATION -------------------------------------------------- local function smoothlyFaceStorm(part, targetPosition, dt) if not part or not part.Parent then return end local position = part.Position local direction = targetPosition - position if direction.Magnitude < 0.01 then return end direction = direction.Unit local targetRotation = CFrame.lookAt( position, position + direction ) -- Smooth rotation instead of randomly changing -- the CFrame every frame. local rotationAlpha = math.clamp(dt * 5, 0, 1) part.CFrame = part.CFrame:Lerp( targetRotation, rotationAlpha ) end -------------------------------------------------- -- MAIN SUCTION LOOP -------------------------------------------------- RunService.Heartbeat:Connect(function(dt) if not object or not object.Parent then return end local objectPos = object:GetPivot().Position for i = #attractedParts, 1, -1 do local obj = attractedParts[i] if not obj or not obj.Parent or isCharacterPart(obj) then shakingParts[obj] = nil table.remove(attractedParts, i) continue end local dist = (obj.Position - objectPos).Magnitude -------------------------------------------------- -- INITIAL SHAKE -------------------------------------------------- local data = shakingParts[obj] if not data then data = { Time = 0, Started = false } shakingParts[obj] = data end -------------------------------------------------- -- SHAKE BEFORE PULLING -------------------------------------------------- if not data.Started then data.Time += dt local shakeTime = math.clamp( data.Time / PRE_SHAKE_TIME, 0, 1 ) -- Make the shaking gradually become stronger. local strength = SHAKE_STRENGTH * math.sin(shakeTime * math.pi / 2) local t = os.clock() * SHAKE_FREQUENCY local shakeX = math.sin(t * 1.17) * strength local shakeY = math.sin(t * 1.43) * strength local shakeZ = math.cos(t * 1.31) * strength -------------------------------------------------- -- KEEP THE ORIGINAL ROTATION -------------------------------------------------- local baseRotation = data.BaseRotation if not baseRotation then baseRotation = obj.CFrame.Rotation data.BaseRotation = baseRotation end obj.CFrame = CFrame.new( obj.Position + Vector3.new( shakeX, shakeY, shakeZ ) ) * baseRotation -------------------------------------------------- -- BLACKEN EVEN WHILE SHAKING -------------------------------------------------- updateBlackening(obj, dist) -------------------------------------------------- -- START PULLING -------------------------------------------------- if data.Time >= PRE_SHAKE_TIME then data.Started = true end continue end -------------------------------------------------- -- BLACKEN AS IT APPROACHES -------------------------------------------------- updateBlackening(obj, dist) -------------------------------------------------- -- FINAL EATING SHAKE -------------------------------------------------- if dist <= EAT_DISTANCE then if not data.FinalShake then data.FinalShake = true data.FinalShakeTime = 0 end data.FinalShakeTime += dt local finalAlpha = math.clamp( data.FinalShakeTime / SHAKE_TIME, 0, 1 ) local finalStrength = 0.8 * (0.5 + finalAlpha * 0.5) local t = os.clock() * 30 local shakeOffset = Vector3.new( math.sin(t * 1.7), math.sin(t * 2.3), math.cos(t * 1.9) ) * finalStrength obj.CFrame = CFrame.new( objectPos + shakeOffset ) * CFrame.Angles( math.sin(t * 1.3) * 0.25, math.sin(t * 1.7) * 0.25, math.cos(t * 1.5) * 0.25 ) -- Make completely black at the end. obj.Color = Color3.new(0, 0, 0) -------------------------------------------------- -- EAT -------------------------------------------------- if data.FinalShakeTime >= SHAKE_TIME then shakingParts[obj] = nil obj:Destroy() table.remove( attractedParts, i ) onPartDestroyed() end continue end -------------------------------------------------- -- SMOOTH SUCTION -------------------------------------------------- local direction = objectPos - obj.Position if direction.Magnitude > 0.01 then direction = direction.Unit local moveDistance = math.min( SUCTION_SPEED * dt, dist ) local newPosition = obj.Position + direction * moveDistance -------------------------------------------------- -- MOVE -------------------------------------------------- obj.CFrame = CFrame.new(newPosition) * obj.CFrame.Rotation -------------------------------------------------- -- SMOOTHLY ROTATE TOWARD THE STORM -------------------------------------------------- smoothlyFaceStorm( obj, objectPos, dt ) end end end) local function getPhaseSettings() local phase = currentPhase if phase == 1 then return { minHeight = 5, maxHeight = 30, speed = 1, move = true } elseif phase == 1.5 then return { minHeight = 8, maxHeight = 32, speed = 0.9, move = true } elseif phase == 2 then return { minHeight = 10, maxHeight = 35, speed = 0.8, move = true } elseif phase == 2.5 then return { minHeight = 12, maxHeight = 38, speed = 0.75, move = true } elseif phase == 3 then return { minHeight = 15, maxHeight = 40, speed = 0.7, move = true } elseif phase == 3.5 then return { minHeight = 18, maxHeight = 43, speed = 0.6, move = true } elseif phase == 4 then return { minHeight = 100, maxHeight = 150, speed = 0.1, move = true } elseif phase == 4.5 then return { minHeight = 70, maxHeight = 90, speed = 0.1, move = true } elseif phase == 5 then return { minHeight = 25, maxHeight = 90, speed = 0.1, move = true } else -- Phase 6 return { minHeight = 35, maxHeight = 95, speed = 0.3, move = true } end end local function setSoundDistanceVolume(sound, sourcePosition, maxDistance, maxVolume) if not character or not character:FindFirstChild("HumanoidRootPart") then return end local playerPos = character.HumanoidRootPart.Position local distance = (playerPos - sourcePosition).Magnitude if distance >= maxDistance then sound.Volume = 0 else local alpha = distance / maxDistance sound.Volume = maxVolume * (1 - alpha) end end coroutine.wrap(function() while true do local settings = getPhaseSettings() if settings.move and object and object.Parent then local startCFrame = object:GetPivot() local playerPivot = character:GetPivot() local randomOffset = Vector3.new( math.random(-50, 50), math.random(settings.minHeight, settings.maxHeight), math.random(-50, 50) ) local targetPos = playerPivot.Position + randomOffset targetPos = Vector3.new( targetPos.X, math.max( targetPos.Y, playerPivot.Position.Y + settings.minHeight ), targetPos.Z ) local startPos = startCFrame.Position local direction = targetPos - startPos if direction.Magnitude < 1 then task.wait(1) continue end -- Direction the Storm should face local flatDirection = Vector3.new( direction.X, 0, direction.Z ) if flatDirection.Magnitude > 0.01 then flatDirection = flatDirection.Unit else flatDirection = startCFrame.LookVector end -- Smoothly turn toward the destination local targetRotation = CFrame.lookAt( startPos, startPos + flatDirection ).Rotation local duration = math.random( 3 / settings.speed, 10 / settings.speed ) local elapsed = 0 while elapsed < duration and object and object.Parent do local dt = RunService.Heartbeat:Wait() elapsed += dt local alpha = math.clamp( elapsed / duration, 0, 1 ) -- Smooth movement local newPosition = startPos:Lerp( targetPos, alpha ) -- Smooth turning local turnAlpha = math.clamp( dt * 0.4, 0, 1 ) local currentRotation = object:GetPivot().Rotation local newRotation = currentRotation:Lerp( targetRotation, turnAlpha ) object:PivotTo( CFrame.new(newPosition) * newRotation ) end else task.wait(0.1) end end end)() coroutine.wrap(function() while true do task.wait(3) local objectPos = object:GetPivot().Position -- Find players within 700 studs local nearbyPlayers = {} for _, plr in ipairs(Players:GetPlayers()) do local char = plr.Character local root = char and char:FindFirstChild("HumanoidRootPart") if root then local distance = (root.Position - objectPos).Magnitude if distance <= 700 then table.insert(nearbyPlayers, plr) end end end -- Nobody is close enough if #nearbyPlayers == 0 then continue end local skullTemplate = game:GetObjects("rbxassetid://16940644099")[1] local skull = skullTemplate:Clone() skull.Parent = game.Workspace local launchSound = Instance.new("Sound") launchSound.SoundId = "rbxassetid://127670808213759" launchSound.Volume = 2 launchSound.RollOffMode = Enum.RollOffMode.Linear launchSound.RollOffMinDistance = 0 launchSound.RollOffMaxDistance = 700 launchSound.Parent = workspace launchSound:Play() local launchConnection launchConnection = RunService.Heartbeat:Connect(function() if not launchSound or not launchSound.Parent or not skull or not skull.Parent then if launchConnection then launchConnection:Disconnect() end return end if not character or not character:FindFirstChild("HumanoidRootPart") then launchSound.Volume = 0 return end local playerPos = character.HumanoidRootPart.Position local soundPos = skull:GetPivot().Position local distance = (playerPos - soundPos).Magnitude if distance >= 700 then launchSound.Volume = 0 else local alpha = distance / 700 launchSound.Volume = 2 * (1 - alpha) end end) task.delay(5, function() if launchConnection then launchConnection:Disconnect() end if launchSound then launchSound:Destroy() end end) launchSound.Parent = game.Workspace launchSound:Play() local launchConnection launchConnection = RunService.Heartbeat:Connect(function() if not launchSound or not launchSound.Parent or not skull or not skull.Parent then if launchConnection then launchConnection:Disconnect() end return end setSoundDistanceVolume( launchSound, skull:GetPivot().Position, 700, 2 ) end) task.delay(5, function() if launchConnection then launchConnection:Disconnect() end end) local objectCFrame = object:GetPivot() local spawnOffset = objectCFrame.LookVector * 5 local skullPosition = objectCFrame.Position + spawnOffset skull:PivotTo( CFrame.new(skullPosition) * objectCFrame.Rotation ) -------------------------------------------------- -- RANDOM PLAYER OR RANDOM DIRECTION -------------------------------------------------- local skullDir -- 70% chance to target a random nearby player if math.random(1, 100) <= 70 then local targetPlayer = nearbyPlayers[math.random(1, #nearbyPlayers)] local targetCharacter = targetPlayer.Character local targetRoot = targetCharacter and targetCharacter:FindFirstChild("HumanoidRootPart") if targetRoot then skullDir = (targetRoot.Position - skullPosition).Unit end end -- If no target was selected, shoot randomly if not skullDir then skullDir = Vector3.new( math.random(-100, 100), math.random(-30, 50), math.random(-100, 100) ).Unit end skull:PivotTo( CFrame.lookAt( skullPosition, skullPosition + skullDir ) ) -------------------------------------------------- -- SKULL MOVEMENT -------------------------------------------------- local speed = 50 local moving = true local exploded = false coroutine.wrap(function() while skull and skull.Parent and moving do local dt = RunService.Heartbeat:Wait() local newPos = skull:GetPivot().Position + skullDir * speed * dt skull:PivotTo( CFrame.new(newPos) * skull:GetPivot().Rotation ) end end)() -------------------------------------------------- -- EXPLOSION / DAMAGE -------------------------------------------------- local function explodeSkull() if exploded or not skull or not skull.Parent then return end exploded = true moving = false local explosionPos = skull:GetPivot().Position local explosion = Instance.new("Explosion") explosion.Position = explosionPos explosion.BlastRadius = 10 explosion.BlastPressure = 0 explosion.DestroyJointRadiusPercent = 0 explosion.Parent = game.Workspace local explodeSound = Instance.new("Sound") explodeSound.SoundId = "rbxassetid://90854697257230" explodeSound.Volume = 0 explodeSound.Parent = game.Workspace explodeSound:Play() local explosionConnection explosionConnection = RunService.Heartbeat:Connect(function() if not explodeSound or not explodeSound.Parent then if explosionConnection then explosionConnection:Disconnect() end return end setSoundDistanceVolume( explodeSound, explosionPos, 700, 2 ) end) task.delay(5, function() if explosionConnection then explosionConnection:Disconnect() end end) -- Damage nearby players for _, plr in ipairs(Players:GetPlayers()) do local char = plr.Character local root = char and char:FindFirstChild("HumanoidRootPart") local humanoid = char and char:FindFirstChildWhichIsA("Humanoid") if root and humanoid then local distance = (root.Position - explosionPos).Magnitude if distance <= 10 then humanoid:TakeDamage(45) end end end skull:Destroy() end -------------------------------------------------- -- TOUCH DETECTION -------------------------------------------------- for _, desc in ipairs(skull:GetDescendants()) do if desc:IsA("BasePart") then desc.CanCollide = false desc.Touched:Connect(function(other) if other and other.Parent then explodeSkull() end end) end end -------------------------------------------------- -- AUTO DELETE AFTER 17 SECONDS -------------------------------------------------- task.delay(17, function() if skull and skull.Parent then moving = false skull:Destroy() end end) end end)() disableCollisions(object) -------------------------------------------------- -- đŸŽĩ WHATHAVEYOUDONE MUSIC -- ONLY PLAYS DURING PHASE 4–6 -- QUIET BUT STILL AUDIBLE -------------------------------------------------- local sound = Instance.new("Sound") sound.SoundId = getcustomasset("WHATHAVEYOUDONE.mp3") sound.Volume = 0 sound.Parent = game.Workspace sound.Looped = true local MUSIC_MIN_VOLUME = 0.30 local MUSIC_MAX_VOLUME = 0.48 local MUSIC_START_DISTANCE = 700 local MUSIC_END_DISTANCE = 2500 local function isMusicPhase() return currentPhase == 4 or currentPhase == 4.5 or currentPhase == 5 or currentPhase == 6 end -------------------------------------------------- -- đŸŽĩ MUSIC DISTANCE + PHASE CONTROL -------------------------------------------------- RunService.Heartbeat:Connect(function() if not sound or not sound.Parent then return end if not character or not character:FindFirstChild("HumanoidRootPart") or not object or not object.Parent then sound.Volume = 0 return end -------------------------------------------------- -- PHASE 1–3.5 = COMPLETELY SILENT -------------------------------------------------- if not isMusicPhase() then sound.Volume = 0 if sound.IsPlaying then sound:Pause() end return end -------------------------------------------------- -- PHASE 4–6 = MUSIC ACTIVE -------------------------------------------------- if not sound.IsPlaying then sound:Play() end local playerPos = character.HumanoidRootPart.Position local witherPos = object:GetPivot().Position local distance = (playerPos - witherPos).Magnitude -------------------------------------------------- -- TOO FAR = SILENT -------------------------------------------------- if distance >= MUSIC_END_DISTANCE then sound.Volume = 0 -------------------------------------------------- -- CLOSE = STILL QUIET -------------------------------------------------- elseif distance <= MUSIC_START_DISTANCE then sound.Volume = MUSIC_MAX_VOLUME -------------------------------------------------- -- DISTANCE FADE -------------------------------------------------- else local alpha = (distance - MUSIC_START_DISTANCE) / (MUSIC_END_DISTANCE - MUSIC_START_DISTANCE) sound.Volume = MUSIC_MAX_VOLUME - ( (MUSIC_MAX_VOLUME - MUSIC_MIN_VOLUME) * alpha ) end end) -- Music distance fade RunService.Heartbeat:Connect(function() if not character or not character:FindFirstChild("HumanoidRootPart") then return end local playerPos = character.HumanoidRootPart.Position local witherPos = object:GetPivot().Position local distance = (playerPos - witherPos).Magnitude -- Full volume at 0 studs, silent at 700 studs local fadeStart = 300 local fadeEnd = 700 if distance <= fadeStart then sound.Volume = 2 elseif distance >= fadeEnd then sound.Volume = 0 else local alpha = (distance - fadeStart) / (fadeEnd - fadeStart) sound.Volume = 2 * (1 - alpha) end end) -- 700+ STUDS DISTANCE SOUND EFFECT -- ONLY ACTIVE DURING PHASE 4 TO PHASE 6 local farSound = Instance.new("Sound") farSound.SoundId = "rbxassetid://117417134619684" farSound.Volume = 0 farSound.Looped = true farSound.Parent = game.Workspace farSound:Play() -- RANDOM SOUNDS FOR PHASE 4 TO 6 -- FADES OUT FROM 700 TO 1400 STUDS local randomPhaseSounds = { "rbxassetid://104920509805458", "rbxassetid://73727370500420", "rbxassetid://18114288672", "rbxassetid://137355274755922" } local randomSound = nil local randomSoundPlaying = false local function playRandomPhaseSound() if randomSoundPlaying then return end randomSoundPlaying = true local soundId = randomPhaseSounds[ math.random(1, #randomPhaseSounds) ] randomSound = Instance.new("Sound") randomSound.SoundId = soundId randomSound.Volume = 0 randomSound.Looped = false randomSound.Parent = game.Workspace randomSound:Play() -- Distance fade local fadeConnection fadeConnection = RunService.Heartbeat:Connect(function() if not randomSound or not randomSound.Parent then fadeConnection:Disconnect() return end if not character or not character:FindFirstChild("HumanoidRootPart") then randomSound.Volume = 0 return end local playerPos = character.HumanoidRootPart.Position local soundPos = object:GetPivot().Position local distance = (playerPos - soundPos).Magnitude if distance <= 700 then randomSound.Volume = 2 elseif distance >= 1400 then randomSound.Volume = 0 else local alpha = (distance - 700) / (1400 - 700) randomSound.Volume = 2 * (1 - alpha) end end) randomSound.Ended:Wait() if fadeConnection then fadeConnection:Disconnect() end if randomSound then randomSound:Destroy() randomSound = nil end randomSoundPlaying = false end -- Randomly play sounds only during Phase 4–6 coroutine.wrap(function() while true do task.wait(math.random(8, 18)) local phaseAllowed = currentPhase == 4 or currentPhase == 4.5 or currentPhase == 5 or currentPhase == 6 if phaseAllowed then coroutine.wrap(playRandomPhaseSound)() end end end)() -- Stop the random sound when leaving Phase 4–6 RunService.Heartbeat:Connect(function() local phaseAllowed = currentPhase == 4 or currentPhase == 4.5 or currentPhase == 5 or currentPhase == 6 if not phaseAllowed and randomSound then randomSound:Stop() randomSound:Destroy() randomSound = nil randomSoundPlaying = false end end) RunService.Heartbeat:Connect(function() if not character or not character:FindFirstChild("HumanoidRootPart") then farSound.Volume = 0 return end local playerPos = character.HumanoidRootPart.Position local witherPos = object:GetPivot().Position local distance = (playerPos - witherPos).Magnitude -- Phase 4, 4.5, 5, and 6 only local phaseAllowed = currentPhase == 4 or currentPhase == 4.5 or currentPhase == 5 or currentPhase == 6 if phaseAllowed and distance >= 700 then farSound.Volume = 0.25 else farSound.Volume = 0 end end)