From 4287714cc6f7353ade499d7ee2831f015cbbd121 Mon Sep 17 00:00:00 2001 From: theFox6 Date: Fri, 16 Oct 2020 10:55:49 +0200 Subject: [PATCH] disable weather in caves --- README.md | 5 +- weather/api.lua | 125 ++--------------------------------- weather/engine.lua | 139 +++++++++++++++++++++++++++++++++++++++ weather/init.lua | 1 + weather/rain.lua | 12 ++-- weather/sand.lua | 6 +- weather/settingtypes.txt | 10 +++ weather/snow.lua | 12 ++-- 8 files changed, 175 insertions(+), 135 deletions(-) create mode 100644 weather/engine.lua diff --git a/README.md b/README.md index 799f863..03d5f26 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Weather mod for [Minetest](http://minetest.net/) -[![luacheck][luacheck badge]][luacheck workflow] +[![luacheck][luacheck badge]][luacheck workflow] +[![ContentDB][ContenDB badge]][ContentDB page] License: - Code: LGPL @@ -9,3 +10,5 @@ License: [luacheck badge]: https://github.com/theFox6/minetest_mod_weather/workflows/luacheck/badge.svg [luacheck workflow]: https://github.com/theFox6/minetest_mod_weather/actions?query=workflow%3Aluacheck +[ContentDB badge]: https://content.minetest.net/packages/theFox/weather/shields/title/ +[ContentDB page]: https://content.minetest.net/packages/theFox/weather/ diff --git a/weather/api.lua b/weather/api.lua index b330b8d..f75f9a5 100644 --- a/weather/api.lua +++ b/weather/api.lua @@ -40,16 +40,16 @@ end local default_downfall = { --minimum starting position - min_pos = {x=-15, y=10, z=-15}, + min_pos = {x=-15, y=15, z=-15}, --maximum starting position - max_pos = {x=15, y=10, z=15}, + max_pos = {x=15, y=15, z=15}, --y falling speed falling_speed = 10, --number of textures spawned amount = 15, --the texture size size = 25, - --whether lightning schould be enabled + --whether lightning should be enabled enable_lightning=false, --whether to damage the player damage_player=false, @@ -71,12 +71,10 @@ local default_damage = { function weather_mod.register_downfall(id,def) local name = check_modname_prefix(id) if name == "none" then error("\"none\" means none, thanks") end - if weather_mod.registered_downfalls[name]~=nil then error(name.." is already registered") end + assert(not weather_mod.registered_downfalls[name], name.." is already registered") local ndef = table.copy(def) --what the downfall looks like - if not ndef.texture then - error("no texture given") - end + assert(ndef.texture,"no texture given") set_defaults(ndef,default_downfall) --when to delete the particles if not ndef.exptime then @@ -110,115 +108,4 @@ function weather_mod.disable_downfall(id,disable) weather_mod.registered_downfalls[id].disabled = state end -if minetest.get_modpath("lightning") then - lightning.auto = false - --rawset(lightning,"auto",false) -end - -function weather_mod.handle_lightning(current_weather) - if not minetest.get_modpath("lightning") then return end - if not current_weather then return end - lightning.auto = current_weather.enable_lightning - --rawset(lightning,"auto",current_weather.enable_lightning) - if current_weather.enable_lightning and math.random(1,2) == 1 then - local time = math.floor(math.random(lightning.interval_low/2,lightning.interval_low)) - minetest.after(time, lightning.strike) - end -end - -local do_raycasts = minetest.is_yes(minetest.settings:get_bool('raycast_hitcheck')) -local damage_steps = 0 - -local function handle_damage(damage,player, downfall_origin) - if not damage then return end - damage_steps = damage_steps +1 - if damage_steps < damage.time then return end - damage_steps = 0 - if do_raycasts then - -- this check should be more accurate - local hitpos = vector.add(player:get_pos(),vector.new(0,1,0)) - local ray = minetest.raycast(downfall_origin,hitpos) - local o = ray:next() - if o.type~="object" then return end -- hit node or something - if not o.ref:is_player() then return end -- hit different object - if o.ref:get_player_name() ~= player:get_player_name() then - return --hit other player - end - o = ray:next() - if o then - minetest.log("warning","[weather] raycast hit more after hitting the player\n".. - dump2(o,"o")) - end - else - --check if player is affected by downfall, if it's dark there are nodes nearby - if minetest.get_node_light(player:get_pos(), 0.5) ~= 15 then return end - end - if math.random() < damage.chance then - player:set_hp(player:get_hp()-damage.amount) - end -end - -local function weather_step() - local current_downfall = weather_mod.registered_downfalls[weather.type] - if current_downfall==nil then return end - for _, player in ipairs(minetest.get_connected_players()) do - local ppos = player:get_pos() - - if ppos.y > 120 then return end - - local wind_pos = vector.multiply(weather.wind,-1) - - local minp = vector.add(vector.add(ppos, current_downfall.min_pos),wind_pos) - local maxp = vector.add(vector.add(ppos, current_downfall.max_pos),wind_pos) - - local vel = {x=weather.wind.x,y=-current_downfall.falling_speed,z=weather.wind.z} - local acc = {x=0, y=0, z=0} - - local exp = current_downfall.exptime - - minetest.add_particlespawner({ - amount=current_downfall.amount, time=0.5, - minpos=minp, maxpos=maxp, - minvel=vel, maxvel=vel, - minacc=acc, maxacc=acc, - minexptime=exp, maxexptime=exp, - minsize=current_downfall.size, maxsize=current_downfall.size, - collisiondetection=true, collision_removal=true, - vertical=true, - texture=current_downfall.texture, playername=player:get_player_name() - }) - - local downfall_origin = vector.divide(vector.add(minp,maxp),2) - handle_damage(current_downfall.damage_player,player,downfall_origin) - end -end - -minetest.register_globalstep(function() - if math.random(1, 10000) == 1 then - weather.type = "none" - if minetest.get_modpath("lightning") then - lightning.auto = false - --rawset(lightning,"auto",false) - end - weather_mod.handle_weather_change({type = "none", reason = "globalstep"}) - else - local cnum = 10000 * weather_mod.registered_downfall_count - for id,w in pairs(weather_mod.registered_downfalls) do - if math.random(1, cnum) == 1 then - weather.wind = { - x = math.random(0,10), - y = 0, - z = math.random(0,10) - } - if (not w.disabled) and vector.length(weather.wind) >= w.min_wind then - weather.type = id - weather_mod.handle_lightning(w) - weather_mod.handle_weather_change({type = id, wind = true, reason = "globalstep"}) - break - end - end - end - end - - weather_step() -end) +return weather_mod diff --git a/weather/engine.lua b/weather/engine.lua new file mode 100644 index 0000000..e082a12 --- /dev/null +++ b/weather/engine.lua @@ -0,0 +1,139 @@ +if minetest.get_modpath("lightning") then + lightning.auto = false + --rawset(lightning,"auto",false) +end + +function weather_mod.handle_lightning(current_weather) + if not minetest.get_modpath("lightning") then return end + if not current_weather then return end + lightning.auto = current_weather.enable_lightning + --rawset(lightning,"auto",current_weather.enable_lightning) + if current_weather.enable_lightning and math.random(1,2) == 1 then + local time = math.floor(math.random(lightning.interval_low/2,lightning.interval_low)) + minetest.after(time, lightning.strike) + end +end + +local do_raycasts = minetest.is_yes(minetest.settings:get_bool('raycast_hitcheck')) +local check_light = minetest.is_yes(minetest.settings:get_bool('light_roofcheck',true)) +local damage_steps = 0 + +local function handle_damage(damage,player, downfall_origin) + if not damage then return end + damage_steps = damage_steps +1 + if damage_steps < damage.time then return end + damage_steps = 0 + if do_raycasts then + -- this check should be more accurate + local hitpos = vector.add(player:get_pos(),vector.new(0,1,0)) + local ray = minetest.raycast(downfall_origin,hitpos) + local o = ray:next() + if o.type~="object" then return end -- hit node or something + if not o.ref:is_player() then return end -- hit different object + if o.ref:get_player_name() ~= player:get_player_name() then + return --hit other player + end + o = ray:next() + if o then + minetest.log("warning","[weather] raycast hit more after hitting the player\n".. + dump2(o,"o")) + end + else + --check if player is affected by downfall, if it's dark there are nodes nearby + if minetest.get_node_light(player:get_pos(), 0.5) ~= 15 then return end + end + if math.random() < damage.chance then + player:set_hp(player:get_hp()-damage.amount) + end +end + +local function has_light(minp,maxp) + local manip = minetest.get_voxel_manip() + local e1, e2 = manip:read_from_map(minp, maxp) + local area = VoxelArea:new{MinEdge=e1, MaxEdge=e2} + local data = manip:get_light_data() + + local node_num = 0 + local light = false + + for i in area:iterp(minp, maxp) do + node_num = node_num + 1 + if node_num < 5 then + if data[i] and data[i] == 15 then + light = true + break + end + else + node_num = 0 + end + end + + return light +end + +local function weather_step() + local current_downfall = weather_mod.registered_downfalls[weather.type] + if current_downfall==nil then return end + for _, player in ipairs(minetest.get_connected_players()) do + local ppos = player:get_pos() + + if ppos.y > 120 then return end + + local wind_pos = vector.multiply(weather.wind,-1) + + local minp = vector.add(vector.add(ppos, current_downfall.min_pos),wind_pos) + local maxp = vector.add(vector.add(ppos, current_downfall.max_pos),wind_pos) + + if check_light and not has_light(minp,maxp) then return end + + local vel = {x=weather.wind.x,y=-current_downfall.falling_speed,z=weather.wind.z} + local acc = {x=0, y=0, z=0} + + local exp = current_downfall.exptime + + minetest.add_particlespawner({ + amount=current_downfall.amount, time=0.5, + minpos=minp, maxpos=maxp, + minvel=vel, maxvel=vel, + minacc=acc, maxacc=acc, + minexptime=exp, maxexptime=exp, + minsize=current_downfall.size, maxsize=current_downfall.size, + collisiondetection=true, collision_removal=true, + vertical=true, + texture=current_downfall.texture, playername=player:get_player_name() + }) + + local downfall_origin = vector.divide(vector.add(minp,maxp),2) + handle_damage(current_downfall.damage_player,player,downfall_origin) + end +end + +minetest.register_globalstep(function() + if math.random(1, 10000) == 1 then + weather.type = "none" + if minetest.get_modpath("lightning") then + lightning.auto = false + --rawset(lightning,"auto",false) + end + weather_mod.handle_weather_change({type = "none", reason = "globalstep"}) + else + local cnum = 10000 * weather_mod.registered_downfall_count + for id,w in pairs(weather_mod.registered_downfalls) do + if math.random(1, cnum) == 1 then + weather.wind = { + x = math.random(0,10), + y = 0, + z = math.random(0,10) + } + if (not w.disabled) and vector.length(weather.wind) >= w.min_wind then + weather.type = id + weather_mod.handle_lightning(w) + weather_mod.handle_weather_change({type = id, wind = true, reason = "globalstep"}) + break + end + end + end + end + + weather_step() +end) diff --git a/weather/init.lua b/weather/init.lua index bf62d59..2bd3b9f 100644 --- a/weather/init.lua +++ b/weather/init.lua @@ -31,6 +31,7 @@ weather = (function() end) () dofile(weather_mod.modpath.."/api.lua") +dofile(weather_mod.modpath.."/engine.lua") dofile(weather_mod.modpath.."/rain.lua") dofile(weather_mod.modpath.."/sand.lua") dofile(weather_mod.modpath.."/snow.lua") diff --git a/weather/rain.lua b/weather/rain.lua index 65dcdc1..025043c 100644 --- a/weather/rain.lua +++ b/weather/rain.lua @@ -1,21 +1,21 @@ -- Rain weather_mod.register_downfall("weather:rain",{ - min_pos = {x=-15, y=7, z=-15}, - max_pos = {x= 15, y=7, z= 15}, + min_pos = {x=-15, y=10, z=-15}, + max_pos = {x= 15, y=10, z= 15}, falling_speed=10, amount=25, - exptime=0.8, + exptime=1, size=25, texture="weather_rain.png", enable_lightning=true, }) weather_mod.register_downfall("weather:storm",{ - min_pos = {x = -15, y = 7, z = -15}, - max_pos = {x = 15, y = 7, z = 15}, + min_pos = {x = -15, y = 10, z = -15}, + max_pos = {x = 15, y = 10, z = 15}, falling_speed = 10, amount = 30, - exptime = 0.8, + exptime = 1, size = 30, texture = "weather_rain_dark.png", enable_lightning = true, diff --git a/weather/sand.lua b/weather/sand.lua index e640676..e9d198a 100644 --- a/weather/sand.lua +++ b/weather/sand.lua @@ -1,8 +1,8 @@ weather_mod.register_downfall("weather:sandstorm",{ - min_pos = {x=-20, y=0, z=-20}, - max_pos = {x= 20, y=2, z= 20}, + min_pos = {x=-20, y=-4, z=-20}, + max_pos = {x= 20, y=4, z= 20}, falling_speed=-1, - amount=20, + amount=40, exptime=1, size=25, texture="weather_sand.png", diff --git a/weather/settingtypes.txt b/weather/settingtypes.txt index 83e202b..1297c1f 100644 --- a/weather/settingtypes.txt +++ b/weather/settingtypes.txt @@ -16,3 +16,13 @@ snow_covers_abm (Snow covers for fast PCs) bool false # The raycasts only effect is that they also check the wind # direction. This might cause the performance to drop though. raycast_hitcheck (Raycast hitchecks for fast PCs) bool false + +# Light Roof Check +# +# This setting controls if light data from the VoxelManipulator is +# used to check if the player is under a roof and cannot see the downfall. +# If disabled the weather may appear in caves and under other high roofs. +# If enabled it may have an impact on the performance of a server. +# The light checks are made in the areas around each player. +# Hence it will cost more performance the more players are on a server. +light_roofcheck (Light Roof Check for fast PCs) bool true diff --git a/weather/snow.lua b/weather/snow.lua index 2abe5d2..5352167 100644 --- a/weather/snow.lua +++ b/weather/snow.lua @@ -1,20 +1,20 @@ -- Snow weather_mod.register_downfall("weather:snow",{ - min_pos = {x=-15, y=7, z=-15}, - max_pos = {x= 15, y=7, z= 15}, + min_pos = {x=-15, y=10, z=-15}, + max_pos = {x= 15, y=10, z= 15}, falling_speed=5, amount=15, - exptime=5, + exptime=7, size=25, texture="weather_snow.png", }) weather_mod.register_downfall("weather:hail",{ - min_pos = {x=-15, y=7, z=-15}, - max_pos = {x= 15, y=7, z= 15}, + min_pos = {x=-15, y=10, z=-15}, + max_pos = {x= 15, y=10, z= 15}, falling_speed=25, amount=15, - exptime=0.8, + exptime=1, size=25, texture="weather_hail.png", enable_lightning = true,