2020-06-04 16:36:53 +02:00
local mods_loaded = false
2020-08-19 10:39:44 +02:00
local NIGHT_VISION_RATIO = 0.45
2020-06-04 16:36:53 +02:00
2023-03-27 04:38:49 +02:00
local MINIMUM_LIGHT_LEVEL = 0.2
2023-02-18 09:22:04 +01:00
local water_color = " #3F76E4 "
2022-11-14 23:42:33 +01:00
2022-12-21 14:01:54 +01:00
local mg_name = minetest.get_mapgen_setting ( " mg_name " )
2022-12-24 15:54:48 +01:00
function mcl_weather . set_sky_box_clear ( player , sky , fog )
2022-12-21 15:04:47 +01:00
local pos = player : get_pos ( )
if minetest.get_item_group ( minetest.get_node ( vector.new ( pos.x , pos.y + 1.5 , pos.z ) ) . name , " water " ) ~= 0 then return end
2022-12-21 14:01:54 +01:00
local sc = {
2022-12-27 14:30:33 +01:00
day_sky = " #7BA4FF " ,
day_horizon = " #C0D8FF " ,
2023-02-02 14:42:04 +01:00
dawn_sky = " #7BA4FF " ,
dawn_horizon = " #C0D8FF " ,
2022-12-15 17:46:47 +01:00
night_sky = " #000000 " ,
night_horizon = " #4A6790 " ,
2023-02-02 14:42:04 +01:00
indoors = " #C0D8FF " ,
fog_sun_tint = " #ff5f33 " ,
fog_moon_tint = nil ,
fog_tint_type = " custom "
2022-12-21 14:01:54 +01:00
}
if sky then
sc.day_sky = sky
2023-02-02 14:42:04 +01:00
sc.dawn_sky = sky
2022-12-21 14:01:54 +01:00
end
if fog then
sc.day_horizon = fog
2023-02-02 14:42:04 +01:00
sc.dawn_horizon = fog
2022-12-21 14:01:54 +01:00
end
player : set_sky ( {
type = " regular " ,
sky_color = sc ,
2022-07-31 15:39:29 +02:00
clouds = true ,
} )
end
2022-11-15 23:33:33 +01:00
function mcl_weather . set_sky_color ( player , def )
local pos = player : get_pos ( )
2022-12-24 15:54:48 +01:00
if minetest.get_item_group ( minetest.get_node ( vector.offset ( pos , 0 , 1.5 , 0 ) ) . name , " water " ) ~= 0 then return end
2022-11-15 23:33:33 +01:00
player : set_sky ( {
type = def.type ,
sky_color = def.sky_color ,
clouds = def.clouds ,
} )
end
2023-03-27 04:38:49 +02:00
-- Function to work out light modifier at different times
-- Noon is brightest, midnight is darkest, 0600 and 18000 is in the middle of this
local function get_light_modifier ( time )
-- 0.1 = 0.2
-- 0.4 = 0.8
-- 0.5 = 1
-- 0.6 = 0.8
-- 0.9 = 0.2
local light_multiplier = time * 2
if time > 0.5 then
light_multiplier = 2 * ( 1 - time )
else
light_multiplier = time / 0.5
end
return light_multiplier
end
2017-11-21 01:35:31 +01:00
mcl_weather.skycolor = {
2017-02-20 19:05:26 +01:00
-- Should be activated before do any effect.
2017-02-21 15:09:54 +01:00
active = true ,
2017-02-20 19:05:26 +01:00
-- To skip update interval
force_update = true ,
2017-11-24 01:39:52 +01:00
2017-02-20 19:05:26 +01:00
-- Update interval.
2022-07-31 15:39:29 +02:00
update_interval = 3 ,
2017-02-20 19:05:26 +01:00
2021-05-23 14:44:50 +02:00
-- Main sky colors: starts from midnight to midnight.
2017-02-20 19:05:26 +01:00
-- Please do not set directly. Use add_layer instead.
colors = { } ,
-- min value which will be used in color gradient, usualy its first user given color in 'pure' color.
min_val = 0 ,
-- number of colors while constructing gradient of user given colors
max_val = 1000 ,
-- Table for tracking layer order
layer_names = { } ,
-- To layer to colors table
add_layer = function ( layer_name , layer_color , instant_update )
2017-11-21 01:35:31 +01:00
mcl_weather.skycolor . colors [ layer_name ] = layer_color
table.insert ( mcl_weather.skycolor . layer_names , layer_name )
mcl_weather.skycolor . force_update = true
2017-02-20 19:05:26 +01:00
end ,
2017-11-22 02:19:04 +01:00
current_layer_name = function ( )
return mcl_weather.skycolor . layer_names [ # mcl_weather.skycolor . layer_names ]
end ,
2017-02-20 19:05:26 +01:00
-- Retrieve layer from colors table
retrieve_layer = function ( )
2017-11-22 02:19:04 +01:00
local last_layer = mcl_weather.skycolor . current_layer_name ( )
2017-11-21 01:35:31 +01:00
return mcl_weather.skycolor . colors [ last_layer ]
2017-02-20 19:05:26 +01:00
end ,
-- Remove layer from colors table
remove_layer = function ( layer_name )
2021-03-16 17:43:32 +01:00
for k , name in pairs ( mcl_weather.skycolor . layer_names ) do
2017-02-20 19:05:26 +01:00
if name == layer_name then
2017-11-21 01:35:31 +01:00
table.remove ( mcl_weather.skycolor . layer_names , k )
mcl_weather.skycolor . force_update = true
2017-02-20 19:05:26 +01:00
return
end
end
end ,
2020-08-19 10:39:44 +02:00
-- Wrapper for updating day/night ratio that respects night vision
override_day_night_ratio = function ( player , ratio )
local meta = player : get_meta ( )
2020-08-19 10:53:44 +02:00
local has_night_vision = meta : get_int ( " night_vision " ) == 1
2024-01-22 04:45:19 +01:00
local has_darkness = meta : get_int ( " darkness " ) == 1
2023-12-24 05:48:41 +01:00
local is_visited_shepherd = meta : get_int ( " mcl_shepherd:special " ) == 1
2020-08-19 10:39:44 +02:00
local arg
2024-01-22 04:45:19 +01:00
if has_darkness and not is_visited_shepherd then
arg = 0
else
-- Apply night vision only for dark sky
local is_dark = minetest.get_timeofday ( ) > 0.8 or minetest.get_timeofday ( ) < 0.2 or mcl_weather.state ~= " none "
local pos = player : get_pos ( )
local dim = mcl_worlds.pos_to_dimension ( pos )
if ( has_night_vision or is_visited_shepherd ) and is_dark and dim ~= " nether " and dim ~= " end " then
if ratio == nil then
arg = NIGHT_VISION_RATIO
else
arg = math.max ( ratio , NIGHT_VISION_RATIO )
end
2020-08-19 10:39:44 +02:00
else
2024-01-22 04:45:19 +01:00
arg = ratio
2020-08-19 10:39:44 +02:00
end
end
player : override_day_night_ratio ( arg )
end ,
2017-02-20 19:05:26 +01:00
-- Update sky color. If players not specified update sky for all players.
update_sky_color = function ( players )
2017-11-22 02:19:04 +01:00
-- Override day/night ratio as well
2017-11-21 01:35:31 +01:00
players = mcl_weather.skycolor . utils.get_players ( players )
2017-02-20 19:05:26 +01:00
for _ , player in ipairs ( players ) do
2017-11-23 22:31:39 +01:00
local pos = player : get_pos ( )
2017-11-24 03:10:02 +01:00
local dim = mcl_worlds.pos_to_dimension ( pos )
2022-08-02 11:37:43 +02:00
local has_weather = ( mcl_worlds.has_weather ( pos ) and ( mcl_weather.state == " snow " or mcl_weather.state == " rain " or mcl_weather.state == " thunder " ) and mcl_weather.has_snow ( pos ) ) or ( ( mcl_weather.state == " rain " or mcl_weather.state == " thunder " ) and mcl_weather.has_rain ( pos ) )
2023-02-18 09:22:04 +01:00
local checkname = minetest.get_node ( vector.new ( pos.x , pos.y + 1.5 , pos.z ) ) . name
if minetest.get_item_group ( checkname , " water " ) ~= 0 then
local biome_index = minetest.get_biome_data ( player : get_pos ( ) ) . biome
local biome_name = minetest.get_biome_name ( biome_index )
local biome = minetest.registered_biomes [ biome_name ]
if biome then water_color = biome._mcl_waterfogcolor end
if not biome then water_color = " #3F76E4 " end
if checkname == " mclx_core:river_water_source " or checkname == " mclx_core:river_water_flowing " then water_color = " #0084FF " end
2022-11-14 23:42:33 +01:00
player : set_sky ( { type = " regular " ,
sky_color = {
day_sky = water_color ,
day_horizon = water_color ,
dawn_sky = water_color ,
dawn_horizon = water_color ,
night_sky = water_color ,
night_horizon = water_color ,
2023-02-02 14:42:04 +01:00
indoors = water_color ,
fog_sun_tint = water_color ,
fog_moon_tint = water_color ,
fog_tint_type = " custom "
2022-11-14 23:42:33 +01:00
} ,
2023-02-02 14:42:04 +01:00
clouds = false ,
2022-11-14 23:42:33 +01:00
} )
2022-11-15 23:33:33 +01:00
end
if dim == " overworld " then
2022-12-21 14:01:54 +01:00
local biomesky
local biomefog
if mg_name ~= " v6 " and mg_name ~= " singlenode " then
2023-01-02 22:48:58 +01:00
local biome_index = minetest.get_biome_data ( player : get_pos ( ) ) . biome
local biome_name = minetest.get_biome_name ( biome_index )
local biome = minetest.registered_biomes [ biome_name ]
if biome then
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
biomesky = biome._mcl_skycolor
biomefog = biome._mcl_fogcolor
else
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
end
2022-12-21 14:01:54 +01:00
end
2022-08-01 12:46:46 +02:00
if ( mcl_weather.state == " none " ) then
2020-04-07 00:39:19 +02:00
-- Clear weather
2022-12-21 14:01:54 +01:00
mcl_weather.set_sky_box_clear ( player , biomesky , biomefog )
2020-04-07 00:39:19 +02:00
player : set_sun ( { visible = true , sunrise_visible = true } )
player : set_moon ( { visible = true } )
player : set_stars ( { visible = true } )
2020-08-19 10:39:44 +02:00
mcl_weather.skycolor . override_day_night_ratio ( player , nil )
2022-08-01 12:46:46 +02:00
elseif not has_weather then
local day_color = mcl_weather.skycolor . get_sky_layer_color ( 0.15 )
local dawn_color = mcl_weather.skycolor . get_sky_layer_color ( 0.27 )
local night_color = mcl_weather.skycolor . get_sky_layer_color ( 0.1 )
2022-11-15 23:33:33 +01:00
mcl_weather.set_sky_color ( player , {
type = " regular " ,
2022-08-01 12:46:46 +02:00
sky_color = {
day_sky = day_color ,
day_horizon = day_color ,
dawn_sky = dawn_color ,
dawn_horizon = dawn_color ,
night_sky = night_color ,
night_horizon = night_color ,
} ,
clouds = true ,
} )
player : set_sun ( { visible = false , sunrise_visible = false } )
player : set_moon ( { visible = false } )
player : set_stars ( { visible = false } )
2022-07-31 15:39:29 +02:00
elseif has_weather then
2017-11-24 01:39:52 +01:00
-- Weather skies
2020-04-07 00:39:19 +02:00
local day_color = mcl_weather.skycolor . get_sky_layer_color ( 0.5 )
local dawn_color = mcl_weather.skycolor . get_sky_layer_color ( 0.75 )
local night_color = mcl_weather.skycolor . get_sky_layer_color ( 0 )
2022-11-15 23:33:33 +01:00
mcl_weather.set_sky_color ( player , {
type = " regular " ,
2020-04-07 00:39:19 +02:00
sky_color = {
day_sky = day_color ,
day_horizon = day_color ,
dawn_sky = dawn_color ,
dawn_horizon = dawn_color ,
night_sky = night_color ,
night_horizon = night_color ,
} ,
clouds = true ,
} )
player : set_sun ( { visible = false , sunrise_visible = false } )
player : set_moon ( { visible = false } )
player : set_stars ( { visible = false } )
2017-11-24 01:39:52 +01:00
2023-03-27 04:11:33 +02:00
local light_factor = mcl_weather.get_current_light_factor ( )
2017-11-24 01:39:52 +01:00
if mcl_weather.skycolor . current_layer_name ( ) == " lightning " then
2020-08-19 10:39:44 +02:00
mcl_weather.skycolor . override_day_night_ratio ( player , 1 )
2023-03-27 04:11:33 +02:00
elseif light_factor then
local time = minetest.get_timeofday ( )
2023-03-27 04:38:49 +02:00
local light_multiplier = get_light_modifier ( time )
local new_light = math.max ( light_factor * light_multiplier , MINIMUM_LIGHT_LEVEL )
2023-03-27 04:11:33 +02:00
mcl_weather.skycolor . override_day_night_ratio ( player , new_light )
2017-11-24 01:39:52 +01:00
else
2020-08-19 10:39:44 +02:00
mcl_weather.skycolor . override_day_night_ratio ( player , nil )
2017-11-24 01:39:52 +01:00
end
2017-11-12 04:36:26 +01:00
end
2017-11-24 01:39:52 +01:00
elseif dim == " end " then
2023-01-20 16:41:44 +01:00
local biomesky = " #000000 "
local biomefog = " #A080A0 "
if mg_name ~= " v6 " and mg_name ~= " singlenode " then
local biome_index = minetest.get_biome_data ( player : get_pos ( ) ) . biome
local biome_name = minetest.get_biome_name ( biome_index )
local biome = minetest.registered_biomes [ biome_name ]
if biome then
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
biomesky = biome._mcl_skycolor
biomefog = biome._mcl_fogcolor -- The End biomes seemingly don't use the fog colour, despite having this value according to the wiki. The sky colour is seemingly used for both sky and fog?
else
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
end
end
2017-11-24 01:39:52 +01:00
local t = " mcl_playerplus_end_sky.png "
2020-04-07 00:39:19 +02:00
player : set_sky ( { type = " skybox " ,
2023-01-20 16:41:44 +01:00
base_color = biomesky ,
2020-04-07 00:39:19 +02:00
textures = { t , t , t , t , t , t } ,
clouds = false ,
} )
player : set_sun ( { visible = false , sunrise_visible = false } )
player : set_moon ( { visible = false } )
player : set_stars ( { visible = false } )
2020-08-19 10:39:44 +02:00
mcl_weather.skycolor . override_day_night_ratio ( player , 0.5 )
2017-11-24 01:39:52 +01:00
elseif dim == " nether " then
2023-01-20 16:41:44 +01:00
local biomesky = " #6EB1FF "
local biomefog = " #330808 "
if mg_name ~= " v6 " and mg_name ~= " singlenode " then
local biome_index = minetest.get_biome_data ( player : get_pos ( ) ) . biome
local biome_name = minetest.get_biome_name ( biome_index )
local biome = minetest.registered_biomes [ biome_name ]
if biome then
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
biomesky = biome._mcl_skycolor -- The Nether biomes seemingly don't use the sky colour, despite having this value according to the wiki. The fog colour is used for both sky and fog.
biomefog = biome._mcl_fogcolor
else
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
end
end
2022-11-15 23:33:33 +01:00
mcl_weather.set_sky_color ( player , {
2022-06-19 00:05:47 +02:00
type = " regular " ,
sky_color = {
2023-01-20 16:41:44 +01:00
day_sky = biomefog ,
day_horizon = biomefog ,
dawn_sky = biomefog ,
dawn_horizon = biomefog ,
night_sky = biomefog ,
night_horizon = biomefog ,
2023-02-02 14:42:04 +01:00
indoors = biomefog ,
fog_sun_tint = biomefog ,
fog_moon_tint = biomefog ,
fog_tint_type = " custom "
2022-06-19 00:05:47 +02:00
} ,
2020-04-07 00:39:19 +02:00
clouds = false ,
} )
player : set_sun ( { visible = false , sunrise_visible = false } )
player : set_moon ( { visible = false } )
player : set_stars ( { visible = false } )
2020-08-19 10:39:44 +02:00
mcl_weather.skycolor . override_day_night_ratio ( player , nil )
2017-11-24 01:39:52 +01:00
elseif dim == " void " then
2020-04-07 01:34:11 +02:00
player : set_sky ( { type = " plain " ,
base_color = " #000000 " ,
2020-04-07 00:39:19 +02:00
clouds = false ,
} )
player : set_sun ( { visible = false , sunrise_visible = false } )
player : set_moon ( { visible = false } )
player : set_stars ( { visible = false } )
2017-02-21 13:48:20 +01:00
end
2017-02-20 19:05:26 +01:00
end
end ,
-- Returns current layer color in {r, g, b} format
2020-04-07 00:39:19 +02:00
get_sky_layer_color = function ( timeofday )
2017-11-21 01:35:31 +01:00
if # mcl_weather.skycolor . layer_names == 0 then
2017-02-20 19:05:26 +01:00
return nil
end
2017-11-21 01:35:31 +01:00
-- min timeofday value 0; max timeofday value 1. So sky color gradient range will be between 0 and 1 * mcl_weather.skycolor.max_val.
local rounded_time = math.floor ( timeofday * mcl_weather.skycolor . max_val )
local color = mcl_weather.skycolor . utils.convert_to_rgb ( mcl_weather.skycolor . min_val , mcl_weather.skycolor . max_val , rounded_time , mcl_weather.skycolor . retrieve_layer ( ) )
2017-02-20 19:05:26 +01:00
return color
end ,
utils = {
convert_to_rgb = function ( minval , maxval , current_val , colors )
local max_index = # colors - 1
local val = ( current_val - minval ) / ( maxval - minval ) * max_index + 1.0
local index1 = math.floor ( val )
local index2 = math.min ( math.floor ( val ) + 1 , max_index + 1 )
local f = val - index1
local c1 = colors [ index1 ]
local c2 = colors [ index2 ]
return { r = math.floor ( c1.r + f * ( c2.r - c1.r ) ) , g = math.floor ( c1.g + f * ( c2.g - c1.g ) ) , b = math.floor ( c1.b + f * ( c2.b - c1.b ) ) }
end ,
-- Simply getter. Ether returns user given players list or get all connected players if none provided
get_players = function ( players )
if players == nil or # players == 0 then
2020-06-04 16:36:53 +02:00
if mods_loaded then
players = minetest.get_connected_players ( )
elseif players == nil then
players = { }
end
2017-02-20 19:05:26 +01:00
end
return players
end ,
-- Returns first player sky color. I assume that all players are in same color layout.
get_current_bg_color = function ( )
2017-11-21 01:35:31 +01:00
local players = mcl_weather.skycolor . utils.get_players ( nil )
2021-05-23 14:44:50 +02:00
if players [ 1 ] then
2022-08-09 02:26:31 +02:00
return players [ 1 ] : get_sky ( true ) . sky_color
2017-11-24 01:39:52 +01:00
end
2017-02-20 19:05:26 +01:00
return nil
end
} ,
}
local timer = 0
minetest.register_globalstep ( function ( dtime )
2017-11-21 01:35:31 +01:00
if mcl_weather.skycolor . active ~= true or # minetest.get_connected_players ( ) == 0 then
2017-02-20 19:05:26 +01:00
return
end
2017-11-21 01:35:31 +01:00
if mcl_weather.skycolor . force_update then
mcl_weather.skycolor . update_sky_color ( )
mcl_weather.skycolor . force_update = false
2017-02-20 19:05:26 +01:00
return
end
-- regular updates based on iterval
timer = timer + dtime ;
2017-11-21 01:35:31 +01:00
if timer >= mcl_weather.skycolor . update_interval then
mcl_weather.skycolor . update_sky_color ( )
2017-02-20 19:05:26 +01:00
timer = 0
end
end )
2021-05-28 00:34:58 +02:00
local function initsky ( player )
2022-08-12 15:11:49 +02:00
if player.set_lighting then
player : set_lighting ( { shadows = { intensity = tonumber ( minetest.settings : get ( " mcl_default_shadow_intensity " ) or 0.33 ) } } )
end
2017-11-21 01:35:31 +01:00
if ( mcl_weather.skycolor . active ) then
mcl_weather.skycolor . force_update = true
2017-02-20 19:05:26 +01:00
end
2017-06-05 23:35:45 +02:00
2022-04-13 23:29:14 +02:00
player : set_clouds ( mcl_worlds : get_cloud_parameters ( ) or { height = mcl_worlds.layer_to_y ( 127 ) , speed = { x =- 2 , z = 0 } , thickness = 4 , color = " #FFF0FEF " } )
2017-02-21 13:48:20 +01:00
end
minetest.register_on_joinplayer ( initsky )
minetest.register_on_respawnplayer ( initsky )
2017-11-24 03:48:32 +01:00
mcl_worlds.register_on_dimension_change ( function ( player )
mcl_weather.skycolor . update_sky_color ( { player } )
end )
2020-06-04 16:36:53 +02:00
minetest.register_on_mods_loaded ( function ( )
mods_loaded = true
end )