Загрузка данных


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)