diff --git a/init.lua b/init.lua index 5495896..f740cc0 100644 --- a/init.lua +++ b/init.lua @@ -7,6 +7,7 @@ if minetest.get_modpath("lightning") ~= nil then dofile(modpath.."/thunder.lua") end +-- If not located then embeded skycolor mod version will be loaded. if minetest.get_modpath("skycolor") == nil then dofile(modpath.."/skycolor.lua") end diff --git a/rain.lua b/rain.lua index 55a2534..cd2bb78 100644 --- a/rain.lua +++ b/rain.lua @@ -11,6 +11,8 @@ rain = { -- keeping last timeofday value (rounded). -- Defaulted to non-existing value for initial comparing. sky_last_update = -1, + + init_done = false, } rain.sound_handler = function(player) @@ -22,14 +24,14 @@ rain.sound_handler = function(player) end -- set skybox based on time (uses skycolor api) -rain.set_sky_box = function(player) - skycolor.colors = { - {r=0, g=0, b=0}, +rain.set_sky_box = function() + skycolor.add_layer( + "weather-pack-rain-sky", + {{r=0, g=0, b=0}, {r=85, g=86, b=98}, {r=152, g=150, b=159}, {r=85, g=86, b=98}, - {r=0, g=0, b=0}, - } + {r=0, g=0, b=0}}) skycolor.active = true end @@ -128,9 +130,8 @@ end rain.clear = function() rain.raining = false rain.sky_last_update = -1 - skycolor.active = false - skycolor.colors = {} - skycolor.set_default_sky() + rain.init_done = false + skycolor.remove_layer("weather-pack-rain-sky") for _, player in ipairs(minetest.get_connected_players()) do rain.remove_sound(player) rain.remove_player(player) @@ -146,8 +147,11 @@ minetest.register_globalstep(function(dtime) end) rain.make_weather = function() - rain.raining = true - rain.set_sky_box() + if rain.init_done == false then + rain.raining = true + rain.set_sky_box() + end + for _, player in ipairs(minetest.get_connected_players()) do if (weather.is_underwater(player)) then return false diff --git a/skycolor.lua b/skycolor.lua index 6cec57e..b5005ba 100644 --- a/skycolor.lua +++ b/skycolor.lua @@ -1,38 +1,151 @@ skycolor = { -- Should be activated before do any effect. active = false, + + -- To skip update interval + force_update = true, -- Update interval. update_interval = 15, - -- Main sky colors: starts from midnight to midnight. + -- Main sky colors: starts from midnight to midnight. + -- Please do not set directly. Use add_layer instead. colors = {}, - -- Update sky color. If players not specified update sky for all players. - update_sky_color = function(players) - local timeofday = minetest.get_timeofday() - local rounded_time = math.floor(timeofday * 1000) - local color = skycolor.utils.convert_to_rgb(0, 1000, rounded_time, skycolor.colors) + -- min value which will be used in color gradient, usualy its first user given color in 'pure' color. + min_val = 0, - if players == nil or #players == 0 then - players = minetest.get_connected_players() + -- number of colors while constructing gradient of user given colors + max_val = 1000, + + -- Enables smooth transition between existing sky color and target. + smooth_transitions = true, + + -- Transition between current sky color and new user given. + transition_in_progress = false, + + -- Transition colors are generated automaticly during initialization. + transition_colors = {}, + + -- Time where transition between current color and user given will be done + transition_time = 15, + + -- Tracks how much time passed during transition + transition_timer = 0, + + -- Table for tracking layer order + layer_names = {}, + + -- To layer to colors table + add_layer = function(layer_name, layer_color, instant_update) + skycolor.colors[layer_name] = layer_color + table.insert(skycolor.layer_names, layer_name) + if (instant_update ~= true) then + skycolor.init_transition() end + skycolor.force_update = true + end, + + -- Retrieve layer from colors table + retrieve_layer = function() + local last_layer = skycolor.layer_names[#skycolor.layer_names] + return skycolor.colors[last_layer] + end, + + -- Remove layer from colors table + remove_layer = function(layer_name) + for k, name in ipairs(skycolor.layer_names) do + if name == layer_name then + table.remove(skycolor.layer_names, k) + skycolor.force_update = true + return + end + end + end, + + -- Update sky color. If players not specified update sky for all players. + update_sky_color = function(players) + local color = skycolor.current_sky_layer_color() + if (color == nil) then + skycolor.active = false + skycolor.set_default_sky() + return + end + + players = skycolor.utils.get_players(players) for _, player in ipairs(players) do player:set_sky(color, "plain", nil) end + end, + -- Returns current layer color in {r, g, b} format + current_sky_layer_color = function() + if #skycolor.layer_names == 0 then + return nil + end + + -- min timeofday value 0; max timeofday value 1. So sky color gradient range will be between 0 and 1 * skycolor.max_value. + local timeofday = minetest.get_timeofday() + local rounded_time = math.floor(timeofday * skycolor.max_val) + local color = skycolor.utils.convert_to_rgb(skycolor.min_val, skycolor.max_val, rounded_time, skycolor.retrieve_layer()) + return color + end, + + -- Initialy used only on + update_transition_sky_color = function() + if #skycolor.layer_names == 0 then + skycolor.active = false + skycolor.set_default_sky() + return + end + + local multiplier = 100 + local rounded_time = math.floor(skycolor.transition_timer * multiplier) + if rounded_time >= skycolor.transition_time * multiplier then + skycolor.stop_transition() + return + end + + local color = skycolor.utils.convert_to_rgb(0, skycolor.transition_time * multiplier, rounded_time, skycolor.transition_colors) + + local players = skycolor.utils.get_players(nil) + for _, player in ipairs(players) do + player:set_sky(color, "plain", nil) + end end, -- Reset sky color to game default. If players not specified update sky for all players. + -- Could be sometimes useful but not recomended to use in general case as there may be other color layers + -- which needs to preserve. set_default_sky = function(players) - if players == nil or #players == 0 then - players = minetest.get_connected_players() - end + local players = skycolor.utils.get_players(players) for _, player in ipairs(players) do player:set_sky(nil, "regular", nil) end end, + init_transition = function() + -- sadly default sky returns unpredictible colors so transition mode becomes usable only for user defined color layers + -- Here '2' means that one color layer existed before new added and transition is posible. + if #skycolor.layer_names < 2 then + return + end + + local transition_start_color = skycolor.utils.get_current_bg_color() + if (transition_start_color == nil) then + return + end + local transition_end_color = skycolor.current_sky_layer_color() + skycolor.transition_colors = {transition_start_color, transition_end_color} + skycolor.transition_in_progress = true + end, + + stop_transition = function() + skycolor.transition_in_progress = false + skycolor.transition_colors = {} + skycolor.transition_timer = 0 + end, + utils = { convert_to_rgb = function(minval, maxval, current_val, colors) local max_index = #colors - 1 @@ -43,21 +156,43 @@ skycolor = { 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 + players = minetest.get_connected_players() + end + return players + end, + + -- Returns first player sky color. I assume that all players are in same color layout. + get_current_bg_color = function() + local players = skycolor.utils.get_players(nil) + for _, player in ipairs(players) do + return player:get_sky() + end + return nil end }, } -local timer = -1 -minetest.register_globalstep(function(dtime) - if skycolor.active ~= true then +local timer = 0 +minetest.register_globalstep(function(dtime) + if skycolor.active ~= true or #minetest.get_connected_players() == 0 then return end - -- exceptional first time update - if timer <= 0 then + if skycolor.smooth_transitions and skycolor.transition_in_progress then + skycolor.transition_timer = skycolor.transition_timer + dtime + skycolor.update_transition_sky_color() + return + end + + if skycolor.force_update then skycolor.update_sky_color() - timer = 0 + skycolor.force_update = false return end @@ -68,4 +203,10 @@ minetest.register_globalstep(function(dtime) timer = 0 end +end) + +minetest.register_on_joinplayer(function(player) + if (skycolor.active) then + skycolor.update_sky_color({player}) + end end) \ No newline at end of file diff --git a/snow.lua b/snow.lua index 6f73a97..7b4ec19 100644 --- a/snow.lua +++ b/snow.lua @@ -1,6 +1,7 @@ snow = {} -snow.particles_count = 25 +snow.particles_count = 15 +snow.init_done = false -- calculates coordinates and draw particles for snow weather snow.add_rain_particles = function(player) @@ -14,8 +15,8 @@ snow.add_rain_particles = function(player) pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z}, velocity = {x = math.random(-1,-0.5), y = math.random(-2,-1), z = math.random(-1,-0.5)}, acceleration = {x = math.random(-1,-0.5), y=-0.5, z = math.random(-1,-0.5)}, - expirationtime = 0.6, - size = math.random(0.5, 1), + expirationtime = 2.0, + size = math.random(0.5, 2), collisiondetection = true, collision_removal = true, vertical = true, @@ -27,18 +28,18 @@ snow.add_rain_particles = function(player) end snow.set_sky_box = function() - skycolor.colors = { - {r=0, g=0, b=0}, + skycolor.add_layer( + "weather-pack-snow-sky", + {{r=0, g=0, b=0}, {r=241, g=244, b=249}, - {r=0, g=0, b=0}, - } + {r=0, g=0, b=0}} + ) skycolor.active = true end snow.clear = function() - skycolor.active = false - skycolor.colors = {} - skycolor.set_default_sky() + skycolor.remove_layer("weather-pack-snow-sky") + snow.init_done = false end -- Simple random texture getter @@ -53,12 +54,24 @@ snow.get_texture = function() return texture_name; end +local timer = 0 minetest.register_globalstep(function(dtime) if weather.state ~= "snow" then return false end - snow.set_sky_box() + timer = timer + dtime; + if timer >= 0.5 then + timer = 0 + else + return + end + + if snow.init_done == false then + snow.set_sky_box() + snow.init_done = true + end + for _, player in ipairs(minetest.get_connected_players()) do if (weather.is_underwater(player)) then return false @@ -74,3 +87,4 @@ if weather.reg_weathers.snow == nil then clear = snow.clear } end + diff --git a/weather_core.lua b/weather_core.lua index 34b9dc7..66466be 100644 --- a/weather_core.lua +++ b/weather_core.lua @@ -72,23 +72,23 @@ weather.get_random_pos_by_player_look_dir = function(player) if look_dir.x > 0 then if look_dir.z > 0 then - random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 10) - random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 10) + random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5) + random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5) else - random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 10) - random_pos_z = math.random() + math.random(player_pos.z - 10, player_pos.z + 2.5) + random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5) + random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5) end else if look_dir.z > 0 then - random_pos_x = math.random() + math.random(player_pos.x - 10, player_pos.x + 2.5) - random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 10) + random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5) + random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5) else - random_pos_x = math.random() + math.random(player_pos.x - 10, player_pos.x + 2.5) - random_pos_z = math.random() + math.random(player_pos.z - 10, player_pos.z + 2.5) + random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5) + random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5) end end - random_pos_y = math.random() + math.random(player_pos.y + 1, player_pos.y + 7) + random_pos_y = math.random() + math.random(player_pos.y + 1, player_pos.y + 3) return random_pos_x, random_pos_y, random_pos_z end