local Players = game:GetService("Players") local RunService = game:GetService("RunService") local TweenService = game:GetService("TweenService") local SoundService = game:GetService("SoundService") local Player = Players.LocalPlayer local Camera = workspace.CurrentCamera local PlayerGui = Player:WaitForChild("PlayerGui") local ENTITY_IMAGE = "rbxassetid://16802291466" local GLITCH_PARTICLE = "rbxassetid://107867941" local CHASE_SPEED = 16 local START_TIME = 60 local MIN_SPAWN_DIST = 30 local CORNER_CLEAR = 4 local BTN_COOLDOWN = 7 local BTN_ADD_TIME = 30 local BTN_RECHARGE = 30 local EYE_OFFSET = Vector3.new(0, 1.5, 0) local ENTITY_STUD_W = 10 local ENTITY_STUD_H = 11 local SPAWN_DISTANCE = 500 local function makeSound(id, vol, looped) local s = Instance.new("Sound", SoundService) s.SoundId = "rbxassetid://" .. id s.Volume = vol or 1 s.Looped = looped or false return s end local chaseSound = makeSound("122943965910328", 1, true) local buttonSound = makeSound("137569692043492", 0.9, false) local jumpscareSound = makeSound("88615254175506", 1, false) local hasteEntity = Instance.new("Part") hasteEntity.Name = "Haste_Entity" hasteEntity.Size = Vector3.new(ENTITY_STUD_W, ENTITY_STUD_H, 1) hasteEntity.Transparency = 1 hasteEntity.CanCollide = false hasteEntity.Anchored = true hasteEntity.Position = Vector3.new(0, -9999, 0) hasteEntity.Parent = workspace local billboard = Instance.new("BillboardGui", hasteEntity) billboard.AlwaysOnTop = true billboard.LightInfluence = 0 billboard.Size = UDim2.fromOffset(400, 440) billboard.StudsOffset = Vector3.new(0, 0, 0.52) billboard.Enabled = false local faceImage = Instance.new("ImageLabel", billboard) faceImage.Size = UDim2.fromScale(1, 1) faceImage.Image = ENTITY_IMAGE faceImage.BackgroundTransparency = 1 faceImage.ScaleType = Enum.ScaleType.Stretch local particles = Instance.new("ParticleEmitter", hasteEntity) particles.Texture = GLITCH_PARTICLE particles.Color = ColorSequence.new(Color3.fromRGB(255, 0, 0)) particles.Rate = 0 particles.LightEmission = 0.5 particles.SpreadAngle = Vector2.new(30, 30) local buttonFolder = workspace:FindFirstChild("HasteButtons") or Instance.new("Folder") buttonFolder.Name = "HasteButtons" buttonFolder.Parent = workspace local function buildGui(currentTime) local old = PlayerGui:FindFirstChild("Haste") if old then old:Destroy() end local Haste = Instance.new("ScreenGui") Haste.Name = "Haste" Haste.ZIndexBehavior = Enum.ZIndexBehavior.Sibling Haste.ResetOnSpawn = false -- we handle resetting ourselves Haste.Parent = PlayerGui local Timer = Instance.new("Frame", Haste) Timer.Name = "Timer" Timer.BackgroundColor3 = Color3.fromRGB(97, 87, 115) Timer.BorderSizePixel = 0 Timer.Position = UDim2.new(0.417108059, 0, -0.299007446, 0) Timer.Size = UDim2.new(0, 216, 0, 338) Instance.new("UICorner", Timer) local stroke = Instance.new("UIStroke", Timer) stroke.Thickness = 4.7 local TimeLeft = Instance.new("TextLabel", Timer) TimeLeft.Name = "TimeLeft" TimeLeft.BackgroundTransparency = 1 TimeLeft.BorderSizePixel = 0 TimeLeft.Position = UDim2.new(-2.8257017e-07, 0, 0.744548261, 0) TimeLeft.Size = UDim2.new(0, 216, 0, 88) TimeLeft.Font = Enum.Font.Oswald TimeLeft.TextColor3 = Color3.fromRGB(255, 222, 189) TimeLeft.TextSize = 97 TimeLeft.Text = string.format("%02d:%02d", math.floor(currentTime / 60), currentTime % 60) local Jump = Instance.new("Frame", Haste) Jump.Name = "Jump" Jump.BackgroundColor3 = Color3.fromRGB(0, 0, 0) Jump.BorderSizePixel = 0 Jump.Position = UDim2.new(-0.469512194, 0, -0.633995056, 0) Jump.Size = UDim2.new(5, 1220, 5, 613) Jump.Visible = false Instance.new("UICorner", Jump) local HasteImg = Instance.new("ImageLabel", Haste) HasteImg.Name = "Haste" HasteImg.BackgroundTransparency = 1 HasteImg.BorderSizePixel = 0 HasteImg.Position = UDim2.new(0.0541984737, 0, -0.0843672454, 0) HasteImg.Size = UDim2.new(0, 779, 0, 815) HasteImg.Visible = false HasteImg.Image = ENTITY_IMAGE task.spawn(function() local function shake() while HasteImg and HasteImg.Parent do HasteImg.Position = UDim2.new(0.356, 0, -0.099, 0) task.wait(0.1) HasteImg.Position = UDim2.new(-0.039, 0, 0.175, 0) task.wait(0.1) HasteImg.Position = UDim2.new(0.473, 0, 0.175, 0) task.wait(0.1) HasteImg.Position = UDim2.new(0.054, 0, -0.084, 0) task.wait(0.1) end end HasteImg:GetPropertyChangedSignal("Visible"):Connect(function() if HasteImg.Visible then shake() else HasteImg.Position = UDim2.new(0.19, 0, -0.019, 0) end end) end) return Haste end local isChasing = false local wasChasing = false local isSpawned = false local function despawnHaste() isChasing = false wasChasing = false isSpawned = false billboard.Enabled = false particles.Rate = 0 hasteEntity.Position = Vector3.new(0, -9999, 0) chaseSound:Stop() end local function spawnHaste(eyePos) local angle = math.random() * math.pi * 2 hasteEntity.Position = Vector3.new( eyePos.X + math.cos(angle) * SPAWN_DISTANCE, eyePos.Y, eyePos.Z + math.sin(angle) * SPAWN_DISTANCE ) billboard.Enabled = true particles.Rate = 150 isChasing = true isSpawned = true end local function startRound() local timeLeft = START_TIME local alive = true -- set false on death to stop all loops local gui = buildGui(timeLeft) local function updateTimer() if not PlayerGui:FindFirstChild("Haste") then gui = buildGui(timeLeft) end local lbl = gui:FindFirstChild("Timer") and gui.Timer:FindFirstChild("TimeLeft") if lbl then lbl.Text = string.format("%02d:%02d", math.floor(timeLeft/60), timeLeft%60) end end for _, child in ipairs(buttonFolder:GetChildren()) do child:Destroy() end local function buildButton(hitPos, hitNormal) local model = Instance.new("Model", buttonFolder) model.Name = "HasteButton" local surfCF = CFrame.lookAt(hitPos, hitPos + hitNormal) local frame = Instance.new("Part", model) frame.Name = "Frame"; frame.Size = Vector3.new(2.5, 2.5, 0.25) frame.CFrame = surfCF * CFrame.new(0, 0, -0.125) frame.Color = Color3.fromRGB(30, 30, 30); frame.Material = Enum.Material.Metal frame.Anchored = true; frame.CanCollide = false local btn = Instance.new("Part", model) btn.Name = "ButtonPart"; btn.Shape = Enum.PartType.Cylinder btn.Size = Vector3.new(0.45, 1.8, 1.8) btn.CFrame = surfCF * CFrame.new(0, 0, -0.45) * CFrame.Angles(0, 0, math.rad(90)) btn.Color = Color3.fromRGB(0, 220, 0); btn.Material = Enum.Material.Neon btn.Anchored = true; btn.CanCollide = false local light = Instance.new("PointLight", btn) light.Color = Color3.fromRGB(0, 255, 80); light.Brightness = 2; light.Range = 8 return btn, surfCF end local function randomDir() local v repeat v = Vector3.new(math.random()*2-1, 0, math.random()*2-1) until v.Magnitude > 0.01 return v.Unit end local function trySpawnButton() local root = Player.Character and Player.Character:FindFirstChild("HumanoidRootPart") if not root then return end local eyePos = root.Position + EYE_OFFSET local rp = RaycastParams.new() rp.FilterDescendantsInstances = {Player.Character, hasteEntity, buttonFolder} rp.FilterType = Enum.RaycastFilterType.Exclude for _ = 1, 50 do local ray = workspace:Raycast(eyePos, randomDir() * 150, rp) if ray and math.abs(ray.Normal.Y) < 0.7 then local dist = (ray.Position - eyePos).Magnitude if dist >= MIN_SPAWN_DIST then local right = ray.Normal:Cross(Vector3.new(0,1,0)) if right.Magnitude < 0.01 then right = ray.Normal:Cross(Vector3.new(1,0,0)) end right = right.Unit local lH = workspace:Raycast(ray.Position + right*0.1, right*CORNER_CLEAR, rp) local rH = workspace:Raycast(ray.Position - right*0.1, -right*CORNER_CLEAR, rp) if not lH and not rH then local op = OverlapParams.new() op.FilterDescendantsInstances = {Player.Character, hasteEntity, ray.Instance} op.FilterType = Enum.RaycastFilterType.Exclude local obs = workspace:GetPartBoundsInBox( CFrame.new(ray.Position + ray.Normal * 1.2), Vector3.new(2.2,2.2,2.2), op) if #obs == 0 then local btnPart, surfCF = buildButton(ray.Position, ray.Normal) local prompt = Instance.new("ProximityPrompt", btnPart) prompt.ActionText = "Press"; prompt.ObjectText = "+"..BTN_ADD_TIME.."s" prompt.HoldDuration = 0.08; prompt.RequiresLineOfSight = false prompt.MaxActivationDistance = 8 prompt.Triggered:Connect(function() if not prompt.Enabled then return end prompt.Enabled = false timeLeft += BTN_ADD_TIME buttonSound:Play() updateTimer() if isChasing and timeLeft > 0 then despawnHaste() end local pi = TweenInfo.new(0.08, Enum.EasingStyle.Quad, Enum.EasingDirection.Out) local pCF = surfCF * CFrame.new(0,0,-0.15) * CFrame.Angles(0,0,math.rad(90)) local rCF = surfCF * CFrame.new(0,0,-0.45) * CFrame.Angles(0,0,math.rad(90)) btnPart.Color = Color3.fromRGB(180,0,0) local bl = btnPart:FindFirstChildWhichIsA("PointLight") if bl then bl.Color = Color3.fromRGB(255,60,0) end TweenService:Create(btnPart, pi, {CFrame=pCF}):Play() task.wait(BTN_RECHARGE) if btnPart and btnPart.Parent then btnPart.Color = Color3.fromRGB(0,220,0) if bl then bl.Color = Color3.fromRGB(0,255,80) end TweenService:Create(btnPart, pi, {CFrame=rCF}):Play() prompt.Enabled = true end end) return end end end end end end task.spawn(function() while alive do task.wait(1) timeLeft = math.max(0, timeLeft - 1) updateTimer() if timeLeft <= 0 and not isSpawned then local eyePos = Player.Character and Player.Character:FindFirstChild("HumanoidRootPart") and (Player.Character.HumanoidRootPart.Position + EYE_OFFSET) if eyePos then spawnHaste(eyePos) end end if not isChasing and timeLeft > 0 and timeLeft % BTN_COOLDOWN == 0 then task.spawn(trySpawnButton) end end end) local chaseConn chaseConn = RunService.RenderStepped:Connect(function(dt) if not alive then chaseConn:Disconnect() return end if not isChasing then if chaseSound.IsPlaying then chaseSound:Stop() end return end if not wasChasing then wasChasing = true chaseSound:Play() end local root = Player.Character and Player.Character:FindFirstChild("HumanoidRootPart") if not root then return end local eyePos = root.Position + EYE_OFFSET local toPlayer = eyePos - hasteEntity.Position local dist = toPlayer.Magnitude local next = hasteEntity.Position + toPlayer.Unit * CHASE_SPEED * dt hasteEntity.CFrame = CFrame.lookAt(Vector3.new(next.X, eyePos.Y, next.Z), eyePos) local vp = Camera.ViewportSize local fov = math.rad(Camera.FieldOfView) local cd = (hasteEntity.Position - Camera.CFrame.Position).Magnitude local pps = (vp.Y/2) / (math.tan(fov/2) * math.max(cd, 1)) billboard.Size = UDim2.fromOffset(ENTITY_STUD_W * pps, ENTITY_STUD_H * pps) local intensity = math.clamp(50 / (dist+1), 0, 6) if intensity > 0.3 then Camera.CFrame = Camera.CFrame * CFrame.Angles( math.rad((math.random()*2-1) * intensity * 1.5), math.rad((math.random()*2-1) * intensity * 0.8), 0) end if dist < 7 then chaseSound:Stop() jumpscareSound:Play() local g = PlayerGui:FindFirstChild("Haste") if g then if g:FindFirstChild("Jump") then g.Jump.Visible = true end if g:FindFirstChild("Haste") then g.Haste.Visible = true end end despawnHaste() local hum = Player.Character:FindFirstChildWhichIsA("Humanoid") if hum then hum.Health = 0 end end end) return function() alive = false chaseConn:Disconnect() end end local currentCleanup = nil local function onCharacterAdded(character) local humanoid = character:WaitForChild("Humanoid") if currentCleanup then currentCleanup() end despawnHaste() chaseSound:Stop() jumpscareSound:Stop() task.defer(function() currentCleanup = startRound() end) humanoid.Died:Connect(function() if currentCleanup then currentCleanup() currentCleanup = nil end despawnHaste() chaseSound:Stop() for _, c in ipairs(buttonFolder:GetChildren()) do c:Destroy() end end) end if Player.Character then onCharacterAdded(Player.Character) end Player.CharacterAdded:Connect(onCharacterAdded)