284 lines
7.0 KiB
Lua
284 lines
7.0 KiB
Lua
if minetest.settings:get_bool("enable_weather") == false then
|
|
return
|
|
end
|
|
|
|
local translator = minetest.get_translator
|
|
local S = translator and translator("weather_lite") or function(s) return s end
|
|
|
|
local vadd, vmultiply, vround = vector.add, vector.multiply, vector.round
|
|
local random = math.random
|
|
local snow_covers = minetest.settings:get_bool("weather_snow_covers") ~= false
|
|
|
|
local weather = {
|
|
type = "none",
|
|
wind = {x = 0, y = 0, z = 0}
|
|
}
|
|
|
|
|
|
--
|
|
-- Save and restore weather condition
|
|
--
|
|
|
|
local mod_storage = minetest.get_mod_storage()
|
|
|
|
do
|
|
local saved_weather = minetest.deserialize(
|
|
mod_storage:get_string("weather"))
|
|
if type(saved_weather) == "table" then
|
|
weather = saved_weather
|
|
end
|
|
end
|
|
|
|
minetest.register_on_shutdown(function()
|
|
mod_storage:set_string("weather", minetest.serialize(
|
|
({type = weather.type, wind = weather.wind})))
|
|
end)
|
|
|
|
|
|
--
|
|
-- Registration of weather types
|
|
--
|
|
|
|
weather.registered = {}
|
|
function weather.register(id, def)
|
|
local ndef = table.copy(def)
|
|
weather.registered[id] = ndef
|
|
end
|
|
|
|
-- Rain
|
|
weather.register("rain", {
|
|
desc = S("Rain"),
|
|
falling_speed = 5,
|
|
amount = 6,
|
|
size = 20,
|
|
height = 3,
|
|
vertical = true,
|
|
texture = "weather_lite_rain.png"
|
|
})
|
|
|
|
-- Snow
|
|
weather.register("snow", {
|
|
desc = S("Snow"),
|
|
falling_speed = 2,
|
|
amount = 5,
|
|
size = 35,
|
|
height = 2,
|
|
texture = "weather_lite_snow.png"
|
|
})
|
|
|
|
|
|
--
|
|
-- Change of weather
|
|
--
|
|
|
|
function weather.set(weather_type, wind)
|
|
weather.type = weather_type
|
|
if wind then
|
|
weather.wind = wind
|
|
end
|
|
if minetest.global_exists("sscsm") then
|
|
sscsm.com_send_all("weather_lite:set", {
|
|
type = weather_type,
|
|
wind = wind
|
|
})
|
|
end
|
|
end
|
|
|
|
local function weather_change(disable)
|
|
if weather.type == "none" and not disable then
|
|
for w in pairs(weather.registered) do
|
|
if random(3) == 1 then
|
|
weather.set(w, {
|
|
x = random(0, 8),
|
|
y = 0,
|
|
z = random(0, 8)
|
|
})
|
|
|
|
break
|
|
end
|
|
end
|
|
minetest.after(random(60, 300), function() weather_change(true) end)
|
|
else
|
|
weather.set("none")
|
|
minetest.after(random(1800, 3600), weather_change)
|
|
end
|
|
end
|
|
minetest.after(random(600, 1800), weather_change)
|
|
|
|
|
|
--
|
|
-- Processing players
|
|
--
|
|
|
|
local is_valid_pos = minetest.is_valid_pos
|
|
if not is_valid_pos then
|
|
is_valid_pos = function() return true end
|
|
end
|
|
|
|
-- This is a separate function to prevent "return" from breaking.
|
|
local function process_player(player, current_downfall)
|
|
local player_name = player:get_player_name()
|
|
if not player:is_player() or (sscsm and sscsm.has_sscsms_enabled(player_name)) then
|
|
return
|
|
end
|
|
|
|
local ppos = vround(player:get_pos())
|
|
ppos.y = ppos.y + 1.5
|
|
-- Higher than clouds
|
|
local cloud_height = player:get_clouds().height
|
|
cloud_height = cloud_height ~= 0 and cloud_height or 120
|
|
if not is_valid_pos(ppos) or ppos.y > cloud_height or ppos.y < -8 then return end
|
|
-- Inside liquid
|
|
local head_inside = minetest.get_node_or_nil(ppos)
|
|
local def_inside = head_inside and minetest.registered_nodes[head_inside.name]
|
|
if def_inside and def_inside.drawtype == "liquid" then return end
|
|
-- Too dark, probably not under the sky
|
|
local light = minetest.get_node_light(ppos, 0.5)
|
|
if light and light < 12 then return end
|
|
|
|
local wind_pos = vmultiply(weather.wind, -1)
|
|
local minp = vadd(vadd(ppos, {x = -8, y = current_downfall.height, z = -8}), wind_pos)
|
|
local maxp = vadd(vadd(ppos, {x = 8, y = current_downfall.height, z = 8}), wind_pos)
|
|
local vel = {x = weather.wind.x, y = -current_downfall.falling_speed, z = weather.wind.z}
|
|
local vert = current_downfall.vertical or false
|
|
|
|
minetest.add_particlespawner({
|
|
amount = current_downfall.amount,
|
|
time = 0.1,
|
|
minpos = minp,
|
|
maxpos = maxp,
|
|
minvel = vel,
|
|
maxvel = vel,
|
|
minsize = current_downfall.size,
|
|
maxsize = current_downfall.size,
|
|
collisiondetection = true,
|
|
collision_removal = true,
|
|
vertical = vert,
|
|
texture = current_downfall.texture,
|
|
glow = 1,
|
|
playername = player_name
|
|
})
|
|
end
|
|
|
|
minetest.register_globalstep(function()
|
|
local current_downfall = weather.registered[weather.type]
|
|
if current_downfall == nil then return end
|
|
|
|
for _, player in ipairs(minetest.get_connected_players()) do
|
|
process_player(player, current_downfall)
|
|
end
|
|
end)
|
|
|
|
|
|
--
|
|
-- Snow will cover the blocks and melt after some time
|
|
--
|
|
|
|
if snow_covers then
|
|
-- Temp node to start the node timer
|
|
minetest.register_node("weather_lite:snow_cover", {
|
|
tiles = {"blank.png"},
|
|
drawtype = "signlike",
|
|
paramtype = "light",
|
|
buildable_to = true,
|
|
groups = {not_in_creative_inventory = 1, dig_immediate = 3},
|
|
on_construct = function(pos)
|
|
minetest.get_node_timer(pos):start(random(60, 180))
|
|
minetest.swap_node(pos, {name = "default:snow"})
|
|
end
|
|
})
|
|
|
|
minetest.override_item("default:snow", {
|
|
on_timer = function(pos)
|
|
if weather and weather.type and weather.type == "snow" then
|
|
return true
|
|
end
|
|
|
|
minetest.remove_node(pos)
|
|
end
|
|
})
|
|
|
|
minetest.register_abm({
|
|
label = "Weather: snow cover",
|
|
nodenames = {"group:crumbly", "group:snappy", "group:cracky", "group:choppy"},
|
|
neighbors = {"air"},
|
|
interval = 15,
|
|
chance = 500,
|
|
catch_up = false,
|
|
action = function(pos, node)
|
|
if weather.type == "snow" then
|
|
if pos.y < -8 or pos.y > 120 then return end
|
|
if minetest.registered_nodes[node.name].drawtype == "normal"
|
|
or minetest.registered_nodes[node.name].drawtype == "allfaces_optional" then
|
|
pos.y = pos.y + 1
|
|
if minetest.get_node(pos).name ~= "air" then return end
|
|
local light_day = minetest.get_node_light(pos, 0.5)
|
|
local light_night = minetest.get_node_light(pos, 0)
|
|
if light_day and light_day == 15
|
|
and light_night and light_night < 10 then
|
|
minetest.add_node(pos, {name = "weather_lite:snow_cover"})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
end
|
|
|
|
minetest.register_privilege("weather", {
|
|
description = "Allows changing the weather",
|
|
give_to_singleplayer = minetest.settings:get_bool("creative_mode")
|
|
})
|
|
|
|
minetest.register_chatcommand("weather", {
|
|
params = "<weather>",
|
|
description = S("Setting the weather type"),
|
|
privs = {weather = true},
|
|
func = function(name, param)
|
|
if param and (weather.registered[param] or param == "none") then
|
|
weather.set(param)
|
|
if param == "none" then
|
|
minetest.chat_send_player(name, S("Set clear weather."))
|
|
else
|
|
local setw = weather.registered[param].desc or param:gsub("^%l", string.upper)
|
|
minetest.chat_send_player(name, S("Set weather type: @1.", setw))
|
|
end
|
|
else
|
|
local types = "none"
|
|
for w in pairs(weather.registered) do
|
|
types = types .. ", " .. w
|
|
end
|
|
minetest.chat_send_player(name, S("Avalible weather types: @1.", types))
|
|
end
|
|
end
|
|
})
|
|
|
|
if not minetest.global_exists("sscsm") then
|
|
return
|
|
end
|
|
|
|
sscsm.register({
|
|
name = "weather_lite",
|
|
file = minetest.get_modpath("weather_lite") .. "/sscsm.lua"
|
|
})
|
|
|
|
local liquids
|
|
sscsm.register_on_sscsms_loaded(function(name)
|
|
if not liquids then
|
|
liquids = {}
|
|
for node, def in pairs(minetest.registered_nodes) do
|
|
if def.drawtype == "liquid" then
|
|
liquids[node] = true
|
|
end
|
|
end
|
|
end
|
|
|
|
local player = minetest.get_player_by_name(name)
|
|
sscsm.com_send(name, "weather_lite:set", {
|
|
type = weather.type,
|
|
wind = weather.wind,
|
|
registered = weather.registered,
|
|
cloud_height = player:get_clouds().height,
|
|
liquids = liquids
|
|
})
|
|
end)
|