mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-08-21 09:27:25 +02:00
This commit adds an extra check at the ABMs which prevent the rain from affecting dry biomes, even though there isn't supposed to any rain there.
293 lines
9.3 KiB
Lua
293 lines
9.3 KiB
Lua
local PARTICLES_COUNT_RAIN = tonumber(minetest.settings:get("mcl_weather_rain_particles")) or 500
|
|
local PARTICLES_COUNT_THUNDER = tonumber(minetest.settings:get("mcl_weather_thunder_particles")) or 900
|
|
|
|
local get_connected_players = minetest.get_connected_players
|
|
local mgname = minetest.get_mapgen_setting("mg_name")
|
|
|
|
mcl_weather.rain = {
|
|
-- max rain particles created at time
|
|
particles_count = PARTICLES_COUNT_RAIN,
|
|
|
|
-- flag to turn on/off extinguish fire for rain
|
|
extinguish_fire = true,
|
|
|
|
-- flag useful when mixing weathers
|
|
raining = false,
|
|
|
|
-- keeping last timeofday value (rounded).
|
|
-- Defaulted to non-existing value for initial comparing.
|
|
sky_last_update = -1,
|
|
|
|
init_done = false,
|
|
}
|
|
local update_sound={}
|
|
|
|
local psdef= {
|
|
amount = mcl_weather.rain.particles_count,
|
|
time=0,
|
|
minpos = vector.new(-15,20,-15),
|
|
maxpos = vector.new(15,25,15),
|
|
minvel = vector.new(0,-20,0),
|
|
maxvel = vector.new(0,-15,0),
|
|
minacc = vector.new(0,-0.8,0),
|
|
maxacc = vector.new(0,-0.8,0),
|
|
minexptime = 1,
|
|
maxexptime = 4,
|
|
minsize = 4,
|
|
maxsize= 8,
|
|
collisiondetection = true,
|
|
collision_removal = true,
|
|
vertical = true,
|
|
}
|
|
|
|
local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png"}
|
|
|
|
function mcl_weather.has_rain(pos)
|
|
if not mcl_worlds.has_weather(pos) then return false end
|
|
if mgname == "singlenode" or mgname == "v6" then return true end
|
|
local bd = minetest.registered_biomes[minetest.get_biome_name(minetest.get_biome_data(pos).biome)]
|
|
if bd and bd._mcl_biome_type == "hot" then return false end
|
|
return true
|
|
end
|
|
|
|
function mcl_weather.rain.sound_handler(player)
|
|
return minetest.sound_play("weather_rain", {
|
|
to_player = player:get_player_name(),
|
|
loop = true,
|
|
})
|
|
end
|
|
|
|
-- set skybox based on time (uses skycolor api)
|
|
function mcl_weather.rain.set_sky_box()
|
|
if mcl_weather.state == "rain" then
|
|
mcl_weather.skycolor.add_layer(
|
|
"weather-pack-rain-sky",
|
|
{{r=0, g=0, b=0},
|
|
{r=85, g=86, b=98},
|
|
{r=135, g=135, b=151},
|
|
{r=85, g=86, b=98},
|
|
{r=0, g=0, b=0}})
|
|
mcl_weather.skycolor.active = true
|
|
for _, player in pairs(get_connected_players()) do
|
|
player:set_clouds({color="#5D5D5FE8"})
|
|
end
|
|
end
|
|
end
|
|
|
|
-- no no no NO NO f*.. no. no manual particle creatin' PLS!! this sends EVERY particle over the net.
|
|
function mcl_weather.rain.add_rain_particles(player)
|
|
mcl_weather.rain.last_rp_count = mcl_weather.rain.particles_count
|
|
local l = false
|
|
for k,v in pairs(textures) do
|
|
psdef.texture=v
|
|
l = l or mcl_weather.add_spawner_player(player,"rain"..k,psdef)
|
|
end
|
|
if l then
|
|
update_sound[player:get_player_name()]=true
|
|
end
|
|
end
|
|
|
|
-- register player for rain weather.
|
|
-- basically needs for origin sky reference and rain sound controls.
|
|
function mcl_weather.rain.add_player(player)
|
|
if mcl_weather.players[player:get_player_name()] == nil then
|
|
local player_meta = {}
|
|
player_meta.origin_sky = {player:get_sky(true)}
|
|
mcl_weather.players[player:get_player_name()] = player_meta
|
|
update_sound[player:get_player_name()]=true
|
|
end
|
|
end
|
|
|
|
-- remove player from player list effected by rain.
|
|
-- be sure to remove sound before removing player otherwise soundhandler reference will be lost.
|
|
function mcl_weather.rain.remove_player(player)
|
|
local player_meta = mcl_weather.players[player:get_player_name()]
|
|
if player_meta and player_meta.origin_sky then
|
|
player:set_clouds({color="#FFF0F0E5"})
|
|
mcl_weather.players[player:get_player_name()] = nil
|
|
update_sound[player:get_player_name()]=true
|
|
end
|
|
end
|
|
|
|
-- adds and removes rain sound depending how much rain particles around player currently exist.
|
|
-- have few seconds delay before each check to avoid on/off sound too often
|
|
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
|
|
function mcl_weather.rain.update_sound(player)
|
|
if not update_sound[player:get_player_name()] then return end
|
|
local player_meta = mcl_weather.players[player:get_player_name()]
|
|
if player_meta then
|
|
if player_meta.sound_updated and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
|
return false
|
|
end
|
|
|
|
if player_meta.sound_handler then
|
|
if mcl_weather.rain.last_rp_count == 0 then
|
|
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
|
player_meta.sound_handler = nil
|
|
end
|
|
elseif mcl_weather.rain.last_rp_count > 0 then
|
|
player_meta.sound_handler = mcl_weather.rain.sound_handler(player)
|
|
end
|
|
|
|
player_meta.sound_updated = minetest.get_gametime()
|
|
end
|
|
update_sound[player:get_player_name()]=false
|
|
end
|
|
|
|
-- rain sound removed from player.
|
|
function mcl_weather.rain.remove_sound(player)
|
|
local player_meta = mcl_weather.players[player:get_player_name()]
|
|
if player_meta and player_meta.sound_handler then
|
|
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
|
player_meta.sound_handler = nil
|
|
player_meta.sound_updated = nil
|
|
end
|
|
end
|
|
|
|
-- callback function for removing rain
|
|
function mcl_weather.rain.clear()
|
|
mcl_weather.rain.raining = false
|
|
mcl_weather.rain.sky_last_update = -1
|
|
mcl_weather.rain.init_done = false
|
|
mcl_weather.rain.set_particles_mode("rain")
|
|
mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
|
|
for _, player in pairs(get_connected_players()) do
|
|
mcl_weather.rain.remove_sound(player)
|
|
mcl_weather.rain.remove_player(player)
|
|
mcl_weather.remove_spawners_player(player)
|
|
end
|
|
end
|
|
|
|
minetest.register_globalstep(function(dtime)
|
|
if mcl_weather.state ~= "rain" then
|
|
return false
|
|
end
|
|
mcl_weather.rain.make_weather()
|
|
end)
|
|
|
|
function mcl_weather.rain.make_weather()
|
|
if mcl_weather.rain.init_done == false then
|
|
mcl_weather.rain.raining = true
|
|
mcl_weather.rain.set_sky_box()
|
|
mcl_weather.rain.set_particles_mode(mcl_weather.mode)
|
|
mcl_weather.rain.init_done = true
|
|
end
|
|
|
|
for _, player in pairs(get_connected_players()) do
|
|
local pos=player:get_pos()
|
|
if mcl_weather.is_underwater(player) or not mcl_weather.has_rain(pos) then
|
|
mcl_weather.rain.remove_sound(player)
|
|
mcl_weather.remove_spawners_player(player)
|
|
if mcl_worlds.has_weather(pos) then
|
|
mcl_weather.set_sky_box_clear(player)
|
|
end
|
|
else
|
|
if mcl_weather.has_snow(pos) then
|
|
mcl_weather.rain.remove_sound(player)
|
|
mcl_weather.snow.add_player(player)
|
|
mcl_weather.snow.set_sky_box()
|
|
else
|
|
mcl_weather.rain.add_player(player)
|
|
mcl_weather.rain.add_rain_particles(player)
|
|
mcl_weather.rain.update_sound(player)
|
|
mcl_weather.rain.set_sky_box()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
|
|
function mcl_weather.rain.set_particles_mode(mode)
|
|
if mode == "thunder" then
|
|
psdef.amount=PARTICLES_COUNT_THUNDER
|
|
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
|
else
|
|
psdef.amount=PARTICLES_COUNT_RAIN
|
|
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
|
end
|
|
end
|
|
|
|
if mcl_weather.allow_abm then
|
|
-- ABM for extinguish fire
|
|
minetest.register_abm({
|
|
label = "Rain extinguishes fire",
|
|
nodenames = {"mcl_fire:fire"},
|
|
interval = 2.0,
|
|
chance = 2,
|
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
-- Fire is extinguished if in rain or one of 4 neighbors is in rain
|
|
if mcl_weather.rain.raining and mcl_weather.rain.extinguish_fire then
|
|
local around = {
|
|
{ x = 0, y = 0, z = 0 },
|
|
{ x = -1, y = 0, z = 0 },
|
|
{ x = 1, y = 0, z = 0 },
|
|
{ x = 0, y = 0, z = -1 },
|
|
{ x = 0, y = 0, z = 1 },
|
|
}
|
|
for a=1, #around do
|
|
local apos = vector.add(pos, around[a])
|
|
if mcl_weather.is_outdoor(apos) and mcl_weather.has_rain(apos) then
|
|
minetest.remove_node(pos)
|
|
minetest.sound_play("fire_extinguish_flame", {pos = pos, max_hear_distance = 8, gain = 0.1}, true)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
})
|
|
|
|
-- Slowly fill up cauldrons
|
|
minetest.register_abm({
|
|
label = "Rain fills cauldrons with water",
|
|
nodenames = {"mcl_cauldrons:cauldron", "mcl_cauldrons:cauldron_1", "mcl_cauldrons:cauldron_2"},
|
|
interval = 56.0,
|
|
chance = 1,
|
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
-- Rain is equivalent to a water bottle
|
|
if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) and mcl_weather.has_rain(pos) then
|
|
if node.name == "mcl_cauldrons:cauldron" then
|
|
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_1"})
|
|
elseif node.name == "mcl_cauldrons:cauldron_1" then
|
|
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_2"})
|
|
elseif node.name == "mcl_cauldrons:cauldron_2" then
|
|
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3"})
|
|
elseif node.name == "mcl_cauldrons:cauldron_1r" then
|
|
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_2r"})
|
|
elseif node.name == "mcl_cauldrons:cauldron_2r" then
|
|
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3r"})
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
-- Wetten the soil
|
|
minetest.register_abm({
|
|
label = "Rain hydrates farmland",
|
|
nodenames = {"mcl_farming:soil"},
|
|
interval = 22.0,
|
|
chance = 3,
|
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
|
if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) and mcl_weather.has_rain(pos) then
|
|
if node.name == "mcl_farming:soil" then
|
|
minetest.set_node(pos, {name="mcl_farming:soil_wet"})
|
|
end
|
|
end
|
|
end
|
|
})
|
|
end
|
|
|
|
if mcl_weather.reg_weathers.rain == nil then
|
|
mcl_weather.reg_weathers.rain = {
|
|
clear = mcl_weather.rain.clear,
|
|
light_factor = 0.6,
|
|
-- 10min - 20min
|
|
min_duration = 600,
|
|
max_duration = 1200,
|
|
transitions = {
|
|
[65] = "none",
|
|
[70] = "snow",
|
|
[100] = "thunder",
|
|
}
|
|
}
|
|
end
|