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


local Lighting = game:GetService("Lighting")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

-- ================= НАСТРОЙКИ =================
local Settings = {
	WeatherEnabled = true,
	StartWeather = "Clear",
	MinSeconds = 180,   -- минимум до смены погоды (секунды)
	MaxSeconds = 420,   -- максимум
	Weights = {         -- шанс выпадения (больше = чаще)
		Clear = 30, Rain = 20, Storm = 10, Snow = 15,
		Fog = 10, Hurricane = 5, Tornado = 5,
	},
	TornadoSpeed = 14,
	TornadoHeight = 120,
	TornadoStartDistance = 220,
}
-- =============================================

local FogByWeather = {
	Clear = 0, Rain = 0.08, Storm = 0.15, Snow = 0.15,
	Fog = 0.45, Hurricane = 0.15, Tornado = 0.2,
}
local WindByWeather = {
	Clear = Vector3.new(4, 0, 2), Rain = Vector3.new(8, 0, 4),
	Storm = Vector3.new(25, 0, 10), Snow = Vector3.new(6, 0, 3),
	Fog = Vector3.new(2, 0, 1), Hurricane = Vector3.new(60, 0, 25),
	Tornado = Vector3.new(30, 0, 10),
}

-- плавный туман (читает скрипт дня и ночи)
local fog, fogTarget = 0, 0
task.spawn(function()
	while true do
		task.wait(0.25)
		fog += (fogTarget - fog) * 0.08
		Lighting:SetAttribute("FogAdd", fog)
	end
end)

-- ================= СМЕРЧ =================
local tornado
local layers = {}
local tornadoPos = Vector3.zero
local tornadoDir = Vector3.new(1, 0, 0)
local groundY = 0
local heartbeatConn

local function destroyTornado()
	if heartbeatConn then heartbeatConn:Disconnect() heartbeatConn = nil end
	if tornado then tornado:Destroy() tornado = nil end
	layers = {}
end

local function findGround(x, z)
	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	local ignore = {}
	for _, p in ipairs(Players:GetPlayers()) do
		if p.Character then table.insert(ignore, p.Character) end
	end
	if tornado then table.insert(ignore, tornado) end
	params.FilterDescendantsInstances = ignore
	local r = workspace:Raycast(Vector3.new(x, 500, z), Vector3.new(0, -1000, 0), params)
	return r and r.Position.Y or 0
end

local function spawnTornado()
	destroyTornado()

	local center = Vector3.zero
	for _, p in ipairs(Players:GetPlayers()) do
		local root = p.Character and p.Character:FindFirstChild("HumanoidRootPart")
		if root then center = root.Position break end
	end

	local angle = math.random() * math.pi * 2
	tornadoPos = center + Vector3.new(math.cos(angle), 0, math.sin(angle)) * Settings.TornadoStartDistance
	local toCenter = (center - tornadoPos) * Vector3.new(1, 0, 1)
	tornadoDir = toCenter.Magnitude > 1 and toCenter.Unit or Vector3.new(1, 0, 0)
	groundY = findGround(tornadoPos.X, tornadoPos.Z)

	tornado = Instance.new("Model")
	tornado.Name = "Tornado"

	local count = 14
	local h = Settings.TornadoHeight / count
	for i = 1, count do
		local width = 10 + i * i * 0.45
		local p = Instance.new("Part")
		p.Name = "L" .. i
		p.Shape = Enum.PartType.Cylinder
		p.Size = Vector3.new(h + 1, width, width)
		p.Anchored = true
		p.CanCollide = false
		p.CanQuery = false
		p.CanTouch = false
		p.CastShadow = false
		p.Material = Enum.Material.SmoothPlastic
		p.Color = Color3.fromRGB(95 + i * 3, 98 + i * 3, 100 + i * 3)
		p.Transparency = 0.45
		p.Parent = tornado
		layers[i] = { part = p, y = (i - 0.5) * h, index = i }
	end

	-- пыль у основания
	local dust = Instance.new("ParticleEmitter")
	dust.Texture = "rbxasset://textures/particles/smoke_main.dds"
	dust.Rate = 40
	dust.Lifetime = NumberRange.new(2, 4)
	dust.Speed = NumberRange.new(10, 25)
	dust.SpreadAngle = Vector2.new(180, 180)
	dust.Size = NumberSequence.new(10, 25)
	dust.Transparency = NumberSequence.new({
		NumberSequenceKeypoint.new(0, 0.6),
		NumberSequenceKeypoint.new(1, 1),
	})
	dust.Color = ColorSequence.new(Color3.fromRGB(120, 110, 95))
	dust.Parent = layers[1].part

	tornado.Parent = workspace

	local t, groundTimer = 0, 0
	heartbeatConn = RunService.Heartbeat:Connect(function(dt)
		t += dt
		groundTimer += dt

		-- плавное блуждание направления
		local drift = math.noise(t * 0.08, 0.5, 0.5) * 0.6 * dt
		tornadoDir = CFrame.Angles(0, drift, 0):VectorToWorldSpace(tornadoDir)
		tornadoPos += tornadoDir * Settings.TornadoSpeed * dt

		if groundTimer > 0.3 then
			groundTimer = 0
			local gy = findGround(tornadoPos.X, tornadoPos.Z)
			groundY += (gy - groundY) * 0.5
		end

		for _, l in ipairs(layers) do
			local sway = l.index * 0.7
			local ox = math.cos(t * 2 + l.index * 0.6) * sway
			local oz = math.sin(t * 2 + l.index * 0.6) * sway
			l.part.CFrame = CFrame.new(tornadoPos.X + ox, groundY + l.y, tornadoPos.Z + oz)
				* CFrame.Angles(0, 0, math.pi / 2)
		end
	end)
end

-- ================= СМЕНА ПОГОДЫ =================
local function apply(name)
	if not FogByWeather[name] then return end
	fogTarget = FogByWeather[name]
	workspace.GlobalWind = WindByWeather[name]
	if name == "Tornado" then spawnTornado() else destroyTornado() end
end

local function pickWeather(current)
	local total = 0
	for name, w in pairs(Settings.Weights) do
		if name ~= current then total += w end
	end
	local r = math.random() * total
	for name, w in pairs(Settings.Weights) do
		if name ~= current then
			r -= w
			if r <= 0 then return name end
		end
	end
	return "Clear"
end

Lighting:SetAttribute("Weather", Settings.StartWeather)
apply(Settings.StartWeather)

Lighting:GetAttributeChangedSignal("Weather"):Connect(function()
	apply(Lighting:GetAttribute("Weather"))
end)

task.spawn(function()
	while Settings.WeatherEnabled do
		task.wait(math.random(Settings.MinSeconds, Settings.MaxSeconds))
		Lighting:SetAttribute("Weather", pickWeather(Lighting:GetAttribute("Weather")))
	end
end)