-- Weather mod for Lazarr!
-- It features rain and lightning.
-- Lightning is handled by lzr_sky.

local S = minetest.get_translator("lzr_weather")

lzr_weather = {}

local RAIN_RESPAWN = 5
local LIGHTNING_TIMER_MIN = 1
local LIGHTNING_TIMER_MAX = 35
local LIGHTNING_DURATION = 0.1

-- local weather variables
local current_weather = "clear"
local weather_types = {
	"clear",
	"drizzle",
	"rain",
	"storm"
}
local weather_descriptions = {
	["clear"] = S("Clear"),
	["drizzle"] = S("Drizzle"),
	["rain"] = S("Rain"),
	["storm"] = S("Storm"),
}

local lightning_pr = PseudoRandom(4291990 + minetest.get_us_time())

local last_particlespawner

local rain_timer = RAIN_RESPAWN
local lightning_timer = 0
local next_lightning_at = nil

-- Returns the current weather
function lzr_weather.get_weather()
	return current_weather
end

function lzr_weather.get_weathers()
	return weather_types
end

function lzr_weather.get_weather_description(weather_id)
	return weather_descriptions[weather_id]
end

function lzr_weather.weather_exists(weather)
	for w=1, #weather_types do
		if weather_types[w] == weather then
			return true
		end
	end
	return false
end

-- Set the current weather
function lzr_weather.set_weather(weather)
	current_weather = weather
	rain_timer = RAIN_RESPAWN
	lightning_timer = 0
	if last_particlespawner then
		minetest.delete_particlespawner(last_particlespawner)
	end
end

minetest.register_globalstep(
	function(dtime)
		-- Clear weather: Nothing to do
		local state = lzr_gamestate.get_state()
		if current_weather == "clear" then
			return
		end

		-- Storm weather: Occasional lightning
		if current_weather == "storm" then
			lightning_timer = lightning_timer + dtime
			-- Lightning active: turn off lightning sky after LIGHTNING_DURATION
			if lzr_sky.get_lightning() == true then
				if lightning_timer >= LIGHTNING_DURATION then
					lzr_sky.set_lightning(false)
					lightning_timer = 0
				end
			-- Lightning inactive: turn on lightning sky after a random time
			else
				if not next_lightning_at then
					next_lightning_at = lightning_pr:next(LIGHTNING_TIMER_MIN, LIGHTNING_TIMER_MAX)
				end
				if lightning_timer >= next_lightning_at then
					-- Note: The lightning sky remains active until we manually disable it
					lzr_sky.set_lightning(true)
					lightning_timer = 0
					next_lightning_at = lightning_pr:next(LIGHTNING_TIMER_MIN, LIGHTNING_TIMER_MAX)
				end
			end
		end

		rain_timer = rain_timer + dtime
		if rain_timer < RAIN_RESPAWN then
			return
		end
		rain_timer = 0

		-- Rainy weather: Spawn rain particles
		local amount, fall_speed, min_size, max_size
		if current_weather == "drizzle" then
			amount = 200
			fall_speed = 15
			min_size = 1.8
			max_size = 1.9
		elseif current_weather == "rain" then
			amount = 600
			fall_speed = 16
			min_size = 2.3
			max_size = 2.6
		elseif current_weather == "storm" then
			amount = 1500
			fall_speed = 20
			min_size = 2.6
			max_size = 3.0
		else
			return
		end

		local XZ_BUFFER = 4
		local Y_BUFFER = 3

		local spawn_min, spawn_max
		if lzr_gamestate.get_state() == lzr_gamestate.MENU then
			-- Weather at the "main menu ship" proably needs more work
			spawn_min = {
				x = lzr_globals.MENU_SHIP_POS.x - XZ_BUFFER,
				y = lzr_globals.MENU_SHIP_POS.y + 20,
				z = lzr_globals.MENU_SHIP_POS.z - XZ_BUFFER,
			}
			spawn_max = {
				x = lzr_globals.MENU_SHIP_POS.x + XZ_BUFFER + 20,
				y = lzr_globals.MENU_SHIP_POS.y + 20,
				z = lzr_globals.MENU_SHIP_POS.z + XZ_BUFFER + 35,
			}
		else
			local lpos = lzr_world.get_level_pos()
			local lsize = lzr_world.get_level_size()
			spawn_min = {
				x = lpos.x - XZ_BUFFER,
				y = lpos.y + lsize.y + Y_BUFFER,
				z = lpos.z - XZ_BUFFER,
			}
			spawn_max = {
				x = lpos.x + lsize.x + XZ_BUFFER,
				y = lpos.y + lsize.y + Y_BUFFER,
				z = lpos.z + lsize.z + XZ_BUFFER,
			}
		end
		-- Don't spawn particles if area is not loaded yet
		if minetest.get_node_or_nil(spawn_min) == nil or minetest.get_node_or_nil(spawn_max) == nil then
			return
		end
		
		last_particlespawner = minetest.add_particlespawner({
			amount = amount,
			time = RAIN_RESPAWN,
			minpos = spawn_min,
			maxpos = spawn_max,
			minvel = {x = 0, y = -fall_speed, z = 0},
			maxvel = {x = 0, y = -fall_speed, z = 0},
			minexptime = 3,
			maxexptime = 3,
			minsize = min_size,
			maxsize = max_size,
			collisiondetection = true,
			collision_removal = true,
			vertical = true,
			texture = "lzr_weather_rain.png",
		})

	end
)

