commit 2875526f02d252a5ef3223a78c106b720bf4da0b Author: luk3yx Date: Sun Jul 26 22:57:41 2020 +1200 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..3b3b37f --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +MultiCraft Game mod: weather_lite +================================= + +Authors of source code +---------------------- + +Based on Weather mod + +Copyright (C) Jeija (2013) + +Copyright (C) HybridDog (2015) + +Copyright (C) theFox6 (2018) + +Copyright (C) MultiCraft Development Team (2019-2020) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3.0 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Authors of textures +------------------- + +TeddyDesTodes (textures) CC-BY-SA 3.0: + +* weather_lite_rain.png +* weather_lite_snow.png diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..2b16848 --- /dev/null +++ b/depends.txt @@ -0,0 +1,2 @@ +default +sscsm? diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..fa3b41e --- /dev/null +++ b/init.lua @@ -0,0 +1,272 @@ +if not minetest.settings:get_bool("enable_weather") then + return +end + +local vmultiply, vadd = vector.multiply, vector.add +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", { + falling_speed = 5, + amount = 7, + size = 25, + height = 3, + vertical = true, + texture = "weather_lite_rain.png" +}) + +-- Snow +weather.register("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() + if weather.type == "none" then + for id, _ in pairs(weather.registered) do + if random(3) == 1 then + weather.set(id, { + x = random(0, 8), + y = 0, + z = random(0, 8) + }) + + break + end + end + minetest.after(random(60, 300), weather_change) + 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 = vector.round(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 pairs(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", + 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 = "", + description = "Set weather type", + privs = {weather = true}, + func = function(name, param) + if param and (weather.registered[param] or param == "none") then + weather.set(param) + minetest.chat_send_player(name, "Set weather type: " .. param) + else + local types = "none" + for w, _ in pairs(weather.registered) do + types = types .. ", " .. w + end + minetest.chat_send_player(name, "Avalible weather types: " .. 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) diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..3a0f1d9 --- /dev/null +++ b/mod.conf @@ -0,0 +1,3 @@ +name = weather_lite +depends = default +optional_depends = sscsm diff --git a/sscsm.lua b/sscsm.lua new file mode 100644 index 0000000..a029947 --- /dev/null +++ b/sscsm.lua @@ -0,0 +1,74 @@ +local vmultiply, vadd = vector.multiply, vector.add +local random = math.random + +local weather = { + type = "none", + wind = {x = 0, y = 0, z = 0}, + registered = {}, + liquids = {} +} + +local is_valid_pos = minetest.is_valid_pos +if not is_valid_pos then + is_valid_pos = function() return true end +end + +-- +-- Change of weather +-- + +sscsm.register_on_com_receive("weather_lite:set", function(msg) + for k, v in pairs(msg) do + weather[k] = v + end +end) + +-- +-- Processing players +-- + +assert(minetest.localplayer) +sscsm.every(0.09, function() + local current_downfall = weather.registered[weather.type] + if current_downfall == nil then return end + + local ppos = vector.round(minetest.localplayer:get_pos()) + + ppos.y = ppos.y + 1.5 + -- Higher than clouds + local cloud_height = weather.cloud_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) + if head_inside and weather.liquids[head_inside.name] then return end + + -- Too dark, probably not under the sky + if minetest.get_node_light then + local light = minetest.get_node_light(ppos, 0.5) + if light and light < 12 then return end + 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 + }) +end) diff --git a/textures/weather_lite_rain.png b/textures/weather_lite_rain.png new file mode 100644 index 0000000..3e2a4c6 Binary files /dev/null and b/textures/weather_lite_rain.png differ diff --git a/textures/weather_lite_snow.png b/textures/weather_lite_snow.png new file mode 100644 index 0000000..4db829a Binary files /dev/null and b/textures/weather_lite_snow.png differ