Загрузка данных
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Lighting = game:GetService("Lighting")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
-- ================= НАСТРОЙКИ =================
local Settings = {
TornadoRadius = 45, -- радиус, в котором смерч затягивает
TornadoPull = 90, -- сила затягивания
TornadoLift = 260, -- сила подъёма у центра
WindPush = 12, -- давление ветра на игрока (0 = выключить)
}
-- =============================================
local profiles = {
Clear = { rate = 0, tint = Color3.new(1, 1, 1), bright = 0, sat = 0 },
Rain = { kind = "rain", rate = 350, tint = Color3.fromRGB(205, 215, 230), bright = -0.04, sat = -0.15 },
Storm = { kind = "rain", rate = 800, tint = Color3.fromRGB(170, 180, 200), bright = -0.1, sat = -0.3, lightning = true, wind = 1 },
Snow = { kind = "snow", rate = 220, tint = Color3.fromRGB(225, 235, 255), bright = 0.03, sat = -0.2 },
Fog = { rate = 0, tint = Color3.fromRGB(215, 220, 225), bright = 0, sat = -0.25 },
Hurricane = { kind = "rain", rate = 1000, tint = Color3.fromRGB(160, 170, 185), bright = -0.12, sat = -0.35, wind = 2, slant = true },
Tornado = { rate = 0, tint = Color3.fromRGB(175, 190, 165), bright = -0.1, sat = -0.2, wind = 1 },
}
-- невидимая плита с частицами над камерой
local holder = Instance.new("Part")
holder.Name = "WeatherEmitter"
holder.Anchored = true
holder.CanCollide = false
holder.CanQuery = false
holder.CanTouch = false
holder.Transparency = 1
holder.Size = Vector3.new(70, 1, 70)
holder.Parent = workspace
local rain = Instance.new("ParticleEmitter")
rain.Rate = 0
rain.Lifetime = NumberRange.new(0.8, 1.1)
rain.Speed = NumberRange.new(90, 110)
rain.Size = NumberSequence.new(0.12)
rain.Transparency = NumberSequence.new(0.35)
rain.LightEmission = 0.3
rain.EmissionDirection = Enum.NormalId.Bottom
rain.SpreadAngle = Vector2.new(2, 2)
rain.Acceleration = Vector3.new(0, -60, 0)
rain.Orientation = Enum.ParticleOrientation.VelocityParallel
rain.Parent = holder
local snow = Instance.new("ParticleEmitter")
snow.Rate = 0
snow.Lifetime = NumberRange.new(5, 7)
snow.Speed = NumberRange.new(5, 9)
snow.Size = NumberSequence.new(0.3)
snow.Transparency = NumberSequence.new(0.2)
snow.LightEmission = 0.5
snow.EmissionDirection = Enum.NormalId.Bottom
snow.SpreadAngle = Vector2.new(30, 30)
snow.Acceleration = Vector3.new(2, -2, 1)
snow.Parent = holder
-- цвет погоды
local old = Lighting:FindFirstChild("WeatherColor")
if old then old:Destroy() end
local color = Instance.new("ColorCorrectionEffect")
color.Name = "WeatherColor"
color.Parent = Lighting
local currentTint = Color3.new(1, 1, 1)
local curBright, curSat = 0, 0
local rainRate, snowRate = 0, 0
local flash = 0
local nextFlash = 8
local indoors = false
local function getProfile()
return profiles[Lighting:GetAttribute("Weather") or "Clear"] or profiles.Clear
end
-- проверка, не под крышей ли игрок
task.spawn(function()
while true do
task.wait(0.25)
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { player.Character or workspace, holder }
local hit = workspace:Raycast(camera.CFrame.Position, Vector3.new(0, 60, 0), params)
indoors = hit ~= nil
end
end)
RunService.Heartbeat:Connect(function(dt)
local p = getProfile()
-- плита следует за камерой
holder.CFrame = CFrame.new(camera.CFrame.Position + Vector3.new(0, 25, 0))
-- частицы
local rainTarget = (p.kind == "rain" and not indoors) and p.rate or 0
local snowTarget = (p.kind == "snow" and not indoors) and p.rate or 0
rainRate += (rainTarget - rainRate) * math.clamp(dt * 1.5, 0, 1)
snowRate += (snowTarget - snowRate) * math.clamp(dt * 1.5, 0, 1)
rain.Rate = rainRate
snow.Rate = snowRate
rain.Acceleration = p.slant and Vector3.new(80, -60, 30) or Vector3.new(0, -60, 0)
-- цвет и затемнение
local a = math.clamp(dt * 0.8, 0, 1)
currentTint = currentTint:Lerp(p.tint, a)
curBright += ((p.bright or 0) - curBright) * a
curSat += ((p.sat or 0) - curSat) * a
-- молнии
if p.lightning and not indoors then
nextFlash -= dt
if nextFlash <= 0 then
nextFlash = math.random(6, 16)
flash = 0.7
task.delay(0.14, function() flash = 0.5 end)
end
end
flash *= math.exp(-dt * 7)
color.TintColor = currentTint
color.Brightness = curBright + flash
color.Saturation = curSat
-- физика: смерч и ветер
local char = player.Character
local root = char and char:FindFirstChild("HumanoidRootPart")
local hum = char and char:FindFirstChildOfClass("Humanoid")
if not root or not hum or hum.Health <= 0 then return end
local tor = workspace:FindFirstChild("Tornado")
local base = tor and tor:FindFirstChild("L1")
if base then
local d = (root.Position - base.Position) * Vector3.new(1, 0, 1)
local dist = d.Magnitude
local R = Settings.TornadoRadius
if dist < R and dist > 0.1 then
local k = 1 - dist / R
local dir = d.Unit
local tangent = Vector3.new(-dir.Z, 0, dir.X)
local accel = (-dir * Settings.TornadoPull + tangent * Settings.TornadoPull * 1.2) * k
accel += Vector3.new(0, Settings.TornadoLift * k * k, 0)
local v = root.AssemblyLinearVelocity + accel * dt
if v.Magnitude > 120 then v = v.Unit * 120 end
root.AssemblyLinearVelocity = v
if k > 0.5 then hum:ChangeState(Enum.HumanoidStateType.Freefall) end
end
end
if p.wind and Settings.WindPush > 0 and not indoors then
local w = workspace.GlobalWind
if w.Magnitude > 0.1 then
local push = Vector3.new(w.X, 0, w.Z).Unit * Settings.WindPush * p.wind
root.AssemblyLinearVelocity += push * dt
end
end
end)