commit f9df1d732f70a9b5384aac94cb319bdc8a61a336 Author: Till Affeldt Date: Thu Apr 9 09:03:02 2020 +0200 Sync first working prototype diff --git a/README.md b/README.md new file mode 100644 index 0000000..9db06cd --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +## Assets +- Rain sounds CC0 by Q.K., taken from mymonths +- Thunder sound and puddle texture DWYWPL by Don, Nathan from mymonths at https://github.com/minetest-mods/mymonths +- Snow cover texture WTFPL, taken from mymonths +- Rain texture CC-BY-SA 3.0 from TeddyDesTodes, taken from his weather branch at https://github.com/TeddyDesTodes/minetest/tree/weather +- Snow flake textures CC BY-SA (3.0) by paramat, found in snowdrift mod at https://github.com/paramat/snowdrift +- Snow texture composited from individual snow flakes by paramat. CC-BY-SA (3.0) +- Wind sound CC-BY (3.0) by InspectorJ from https://freesound.org/people/InspectorJ/sounds/376415/ \ No newline at end of file diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..3ae3f59 --- /dev/null +++ b/depends.txt @@ -0,0 +1,9 @@ +default +lightning? +farming? +flowers? +bakedclay? +moreplants? +lemontree? +player_monoids? +playerphysics? \ No newline at end of file diff --git a/description.txt b/description.txt new file mode 100644 index 0000000..1705973 --- /dev/null +++ b/description.txt @@ -0,0 +1,2 @@ +The ultimate weather mod with support not only for rain, snow, and hail, +but also seasons, dynamic puddles and snow layers, wind, regrowing fruit and much more. \ No newline at end of file diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..ec8ffbe --- /dev/null +++ b/init.lua @@ -0,0 +1,53 @@ +assert(minetest.add_particlespawner, "Ultimate Weather requires a more current version of Minetest") +weather_mod = {} + +weather_mod.modname = "ultimate_weather" +weather_mod.modpath = minetest.get_modpath(weather_mod.modname) + +local function getBoolSetting(name, default) + return minetest.is_yes(minetest.settings:get_bool(weather_mod.modname .. "_" .. name) or default) +end + +local function getNumericSetting(name, default) + return tonumber(minetest.settings:get(weather_mod.modname .. "_" .. name) or default) +end + +-- load settings from config file +weather_mod.settings = { + damage = getBoolSetting("damage", true), + weather = getBoolSetting("weather", true), + leaves = getBoolSetting("leaves", true), + snow = getBoolSetting("snow_layers", true), + puddles = getBoolSetting("puddles", true), + skybox = getBoolSetting("skybox", true), + raycasting = getBoolSetting("raycasting", true), + wind = getBoolSetting("wind", true), + flowers = getBoolSetting("flowers", true), + fruit = getBoolSetting("fruit", true), + soil = getBoolSetting("soil", true), + seasons = getBoolSetting("seasons", true), + heat = getNumericSetting("heat", 0), + humidity = getNumericSetting("humidity", 0), + max_height = getNumericSetting("max_height", 120), + min_height = getNumericSetting("min_height", -50) +} + +weather_mod.state = { + current_weather = weather_mod.modname .. ":snowstorm", + heat = 1, + humidity = 1 +} + +-- import core API +dofile(weather_mod.modpath.."/lib/player.lua") +dofile(weather_mod.modpath.."/lib/environment.lua") +dofile(weather_mod.modpath.."/lib/lightning.lua") +dofile(weather_mod.modpath.."/lib/main.lua") + +-- import individual weather types +dofile(weather_mod.modpath.."/weathers/clear.lua") +dofile(weather_mod.modpath.."/weathers/rain.lua") +dofile(weather_mod.modpath.."/weathers/rainstorm.lua") +dofile(weather_mod.modpath.."/weathers/snow.lua") +dofile(weather_mod.modpath.."/weathers/snowstorm.lua") +dofile(weather_mod.modpath.."/weathers/sandstorm.lua") diff --git a/lib/environment.lua b/lib/environment.lua new file mode 100644 index 0000000..dbd1814 --- /dev/null +++ b/lib/environment.lua @@ -0,0 +1,62 @@ +function weather_mod.get_heat(pos) + local base = weather_mod.settings.heat; + local biome = minetest.get_heat(pos) + local height = math.min(math.max(-pos.y / 15, -10), 10) + local random = weather_mod.state.heat; + return (base + biome + height) * random +end + +function weather_mod.get_humidity(pos) + local base = weather_mod.settings.humidity + local biome = minetest.get_humidity(pos) + local random = weather_mod.state.humidity; + return (base + biome) * random +end + +local function is_acceptable_weather_param(value, attr, config) + local min = config.conditions["min_" .. attr] or -10000 + local max = config.conditions["max_" .. attr] or math.huge + minetest.log(attr .. ": " .. value .. " <=> " .. min .. "," .. max) + return value > min and value <= max +end + +function weather_mod.get_weather(pos, wind) + local params = {} + params.heat = weather_mod.get_heat(pos) + params.humidity = weather_mod.get_humidity(pos) + params.windspeed = vector.length(wind) + minetest.log(params.heat .. ", " .. params.humidity .. ", " .. params.windspeed) + + local weather + local priority = -1 + local attributes = { "heat", "humidity", "windspeed" } + for name, config in pairs(weather_mod.weathers) do + minetest.log(dump2(priority, "p")) + if type(priority) ~= "nil" and config.priority < priority then + minetest.log("skipped " .. name) + + elseif type(config.conditions) == "nil" then + weather = name + priority = config.priority + minetest.log("selected (nil) " .. name) + + else + local check = true + for _, attr in ipairs(attributes) do + if not is_acceptable_weather_param(params[attr], attr, config) then + check = false + end + end + if check then + weather = name + priority = config.priority + minetest.log("selected " .. name) + end + end + end + if type(weather) == "nil" then + minetest.log("error", "[Ultimate Weather] No default weather registered") + end + minetest.log(weather) + return weather +end \ No newline at end of file diff --git a/lib/lightning.lua b/lib/lightning.lua new file mode 100644 index 0000000..b2c550a --- /dev/null +++ b/lib/lightning.lua @@ -0,0 +1,3 @@ +if minetest.get_modpath("lightning") then + lightning.auto = false +end \ No newline at end of file diff --git a/lib/main.lua b/lib/main.lua new file mode 100644 index 0000000..811d5d1 --- /dev/null +++ b/lib/main.lua @@ -0,0 +1,130 @@ +local GSCYCLE = 0 +local temperature = 10 +local humidity = 100 +local wind = vector.new(10, 0, -0.25) + +weather_mod.weathers = {} +function weather_mod.register_weather(name, weather) + -- TODO: check and sanitize + weather_mod.weathers[name] = weather +end + +function weather_mod.set_weather(name) + if type(weather_mod.weathers[name]) == nil then + minetest.log("warning", "[Ultimate Weathers] Weather does not exist") + return + end + weather_mod.state.current_weather = name +end + +local function is_outside(player, wind) + local ppos = player:getpos() + local wind_pos = vector.multiply(wind,-1) + local skylight_pos = vector.add(ppos, vector.new(0, 40, 0)) + local downfall_origin = vector.add(skylight_pos,wind_pos) + return weather_mod.is_outdoors(player, downfall_origin) +end + +local function get_texture(particles) + if type(particles.textures) == "nil" or next(particles.textures) == nil then + return particles.texture + end + return particles.textures[math.random(#particles.textures)] +end + +local function spawn_particles(player, particles, wind) + local ppos = player:getpos() + local wind_pos = vector.multiply(wind,-1) + local wind_speed = vector.length(wind) + + local texture = get_texture(particles) + + local minp = vector.add(vector.add(ppos, particles.min_pos),wind_pos) + local maxp = vector.add(vector.add(ppos, particles.max_pos),wind_pos) + + local vel = {x=wind.x,y=-particles.falling_speed,z=wind.z} + local acc = {x=0, y=0, z=0} + + local exp = particles.exptime + local vertical = wind_speed < 3 + + minetest.add_particlespawner({ + amount=particles.amount, + time=0.5, + minpos=minp, + maxpos=maxp, + minvel=vel, + maxvel=vel, + minacc=acc, + maxacc=acc, + minexptime=exp, + maxexptime=exp, + minsize=particles.size, + maxsize=particles.size, + collisiondetection=true, + collision_removal=true, + vertical=vertical, + texture=texture, + player=player:get_player_name() + }) +end + +local sound_handles = {} +local function play_sound(player, sound) + local playername = player:get_player_name() + if not sound_handles[playername] then + local handle = minetest.sound_play(sound, { + to_player = playername, + loop = true + }) + if handle then + sound_handles[playername] = handle + end + end +end + +local function stop_sound(player) + local playername = player:get_player_name() + if sound_handles[playername] then + minetest.sound_stop(sound_handles[playername]) + sound_handles[playername] = nil + end +end + +local function handle_weather() + for _, player in ipairs(minetest.get_connected_players()) do + local ppos = player:getpos() + weather_mod.set_weather(weather_mod.get_weather(ppos, wind)) + + if ppos.y < weather_mod.settings.min_height or ppos.y > weather_mod.settings.max_height then + return + end + + local weather = weather_mod.weathers[weather_mod.state.current_weather] + local clouds = weather.clouds + clouds.speed = vector.multiply(wind, 2) + player:set_clouds(clouds) + + weather_mod.set_headwind(player, wind) + --player:set_clouds({ density = 0.6, color = "#a4a0b6e5", speed = wind }) + + local outdoors = is_outside(player, wind) + if type(weather.particles) ~= "nil" and outdoors then + spawn_particles(player, weather.particles, wind) + end + + if type(weather.sound) ~= "nil" and outdoors then + play_sound(player, weather.sound) + else + stop_sound(player) + end + end +end + +local timer = 0 +minetest.register_globalstep(function(dtime) + timer = timer + dtime + if timer < GSCYCLE then return end + timer = 0 + handle_weather() +end) \ No newline at end of file diff --git a/lib/player.lua b/lib/player.lua new file mode 100644 index 0000000..b71ba41 --- /dev/null +++ b/lib/player.lua @@ -0,0 +1,72 @@ +local mod_player_monoids = minetest.get_modpath("player_monoids") ~= nil +local mod_playerphysics = minetest.get_modpath("playerphysics") ~= nil + +function weather_mod.add_physics(player, effect, value) + local id = weather_mod.modname .. ":" .. effect + if mod_player_monoids then + player_monoids[effect].add_change(player, value, id) + elseif mod_playerphysics then + playerphysics.add_physics_factor(player, effect, id, value) + else + local override = {} + override[effect] = value + player:set_physics_override(override) + end +end + +function weather_mod.remove_physics(player, effect) + local id = weather_mod.modname .. ":" .. effect + if mod_player_monoids then + player_monoids[effect].del_change(player, id) + elseif mod_playerphysics then + playerphysics.remove_physics_factor(player, effect, id) + else + local override = {} + override[effect] = 1 + player:set_physics_override(override) + end +end + +-- function taken from weather mod +-- see https://github.com/theFox6/minetest_mod_weather/blob/master/weather/api.lua#L110 +local function raycast(player, origin) + local hitpos = vector.add(player:get_pos(),vector.new(0,1,0)) + local ray = minetest.raycast(origin,hitpos) + local o = ray:next() + if not o then return false end + if o.type~="object" then return false end -- hit node or something + if not o.ref:is_player() then return false end -- hit different object + if o.ref:get_player_name() ~= player:get_player_name() then + return false --hit other player + end + o = ray:next() + if o then + minetest.log("warning","[ultimate_weather] raycast hit more after hitting the player\n".. + dump2(o,"o")) + end + return true +end + +local function check_light(player) + return minetest.get_node_light(player:getpos(), 0.5) == 15 +end + +function weather_mod.is_outdoors(player, origin) + if weather_mod.settings.raycasting then + return raycast(player, origin) + else + return check_light(player) + end +end + +function weather_mod.set_headwind(player, wind) + local movement = vector.normalize(player:get_player_velocity()) + local product = vector.dot(movement, wind) + -- logistic function, scales between 0 and 2 + -- see https://en.wikipedia.org/wiki/Logistic_function + local L = 2 -- maximum value + local k = 0.1 -- growth rate + local z = 1 -- midpoint + local factor = L / (1 + math.exp(-k * (product - z))) + weather_mod.add_physics(player, "speed", factor) +end \ No newline at end of file diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..7e1d405 --- /dev/null +++ b/mod.conf @@ -0,0 +1,8 @@ +name = ultimate_weather +title = Ultimate Weather +author = TestificateMods +release = 1 +description = """ +The ultimate weather mod with support not only for rain, snow, and hail, +but also seasons, dynamic puddles and snow layers, wind, regrowing fruit and much more. +""" \ No newline at end of file diff --git a/settingtypes.txt b/settingtypes.txt new file mode 100644 index 0000000..1965347 --- /dev/null +++ b/settingtypes.txt @@ -0,0 +1,16 @@ +ultimate_weather_damage (Storms and hail cause damage) bool true +ultimate_weather_weather (Enable weather effects) bool true +ultimate_weather_leaves (Leave color changes in autumn) bool true +ultimate_weather_snow_layers (Place snow layers on ground) bool true +ultimate_weather_puddles (Place rain puddles on ground) bool true +ultimate_weather_skybox (Darken sky during rain) bool true +ultimate_weather_raycasting (Use performance-heavy indoors check) bool false +ultimate_weather_wind (Allow wind to angle rainfall) bool true +ultimate_weather_flowers (Flowers will respawn in spring and die in winter) bool true +ultimate_weather_fruit (Apples and other fruits will regrow) bool true +ultimate_weather_soil (Soil turns wet during rain) bool true +ultimate_weather_seasons (Use seasons instead of permanent summer) bool true +ultimate_weather_base_temperature (Base temperature) float 0 +ultimate_weather_base_humidity (Base humidity) float 0 +ultimate_weather_max_height (Maximum height of weather effects) int 120 +ultimate_weather_min_height (Minimum height of weather effects) int -50 \ No newline at end of file diff --git a/sounds/weather_rain1.ogg b/sounds/weather_rain1.ogg new file mode 100644 index 0000000..acff009 Binary files /dev/null and b/sounds/weather_rain1.ogg differ diff --git a/sounds/weather_rain2.ogg b/sounds/weather_rain2.ogg new file mode 100644 index 0000000..acff009 Binary files /dev/null and b/sounds/weather_rain2.ogg differ diff --git a/sounds/weather_thunder.ogg b/sounds/weather_thunder.ogg new file mode 100644 index 0000000..d7f5326 Binary files /dev/null and b/sounds/weather_thunder.ogg differ diff --git a/sounds/weather_wind.ogg b/sounds/weather_wind.ogg new file mode 100644 index 0000000..4656ca5 Binary files /dev/null and b/sounds/weather_wind.ogg differ diff --git a/textures/weather_hail.png b/textures/weather_hail.png new file mode 100644 index 0000000..4fcfe70 Binary files /dev/null and b/textures/weather_hail.png differ diff --git a/textures/weather_puddle.png b/textures/weather_puddle.png new file mode 100644 index 0000000..de62861 Binary files /dev/null and b/textures/weather_puddle.png differ diff --git a/textures/weather_rain.png b/textures/weather_rain.png new file mode 100644 index 0000000..39b153c Binary files /dev/null and b/textures/weather_rain.png differ diff --git a/textures/weather_rain_dark.png b/textures/weather_rain_dark.png new file mode 100644 index 0000000..3829b36 Binary files /dev/null and b/textures/weather_rain_dark.png differ diff --git a/textures/weather_sand.png b/textures/weather_sand.png new file mode 100644 index 0000000..148a04d Binary files /dev/null and b/textures/weather_sand.png differ diff --git a/textures/weather_snow.png b/textures/weather_snow.png new file mode 100644 index 0000000..7ae6c77 Binary files /dev/null and b/textures/weather_snow.png differ diff --git a/textures/weather_snow_cover.png b/textures/weather_snow_cover.png new file mode 100644 index 0000000..9221a5a Binary files /dev/null and b/textures/weather_snow_cover.png differ diff --git a/textures/weather_snowflake1.png b/textures/weather_snowflake1.png new file mode 100644 index 0000000..ebe7d72 Binary files /dev/null and b/textures/weather_snowflake1.png differ diff --git a/textures/weather_snowflake10.png b/textures/weather_snowflake10.png new file mode 100644 index 0000000..504b9de Binary files /dev/null and b/textures/weather_snowflake10.png differ diff --git a/textures/weather_snowflake11.png b/textures/weather_snowflake11.png new file mode 100644 index 0000000..fb9d678 Binary files /dev/null and b/textures/weather_snowflake11.png differ diff --git a/textures/weather_snowflake12.png b/textures/weather_snowflake12.png new file mode 100644 index 0000000..eab36a8 Binary files /dev/null and b/textures/weather_snowflake12.png differ diff --git a/textures/weather_snowflake2.png b/textures/weather_snowflake2.png new file mode 100644 index 0000000..0efdae4 Binary files /dev/null and b/textures/weather_snowflake2.png differ diff --git a/textures/weather_snowflake3.png b/textures/weather_snowflake3.png new file mode 100644 index 0000000..cdefe2b Binary files /dev/null and b/textures/weather_snowflake3.png differ diff --git a/textures/weather_snowflake4.png b/textures/weather_snowflake4.png new file mode 100644 index 0000000..e6b9cc1 Binary files /dev/null and b/textures/weather_snowflake4.png differ diff --git a/textures/weather_snowflake5.png b/textures/weather_snowflake5.png new file mode 100644 index 0000000..b16111e Binary files /dev/null and b/textures/weather_snowflake5.png differ diff --git a/textures/weather_snowflake6.png b/textures/weather_snowflake6.png new file mode 100644 index 0000000..b64ad12 Binary files /dev/null and b/textures/weather_snowflake6.png differ diff --git a/textures/weather_snowflake7.png b/textures/weather_snowflake7.png new file mode 100644 index 0000000..ea0b7e5 Binary files /dev/null and b/textures/weather_snowflake7.png differ diff --git a/textures/weather_snowflake8.png b/textures/weather_snowflake8.png new file mode 100644 index 0000000..c2a5708 Binary files /dev/null and b/textures/weather_snowflake8.png differ diff --git a/textures/weather_snowflake9.png b/textures/weather_snowflake9.png new file mode 100644 index 0000000..ce3b0a0 Binary files /dev/null and b/textures/weather_snowflake9.png differ diff --git a/weathers/clear.lua b/weathers/clear.lua new file mode 100644 index 0000000..3766597 --- /dev/null +++ b/weathers/clear.lua @@ -0,0 +1,12 @@ +local name = weather_mod.modname .. ":clear" + +local weather = { + priority = 0 +} + +weather.clouds = { + density = 0.3, + color = "#fff0f0c5" +} + +weather_mod.register_weather(name, weather) diff --git a/weathers/rain.lua b/weathers/rain.lua new file mode 100644 index 0000000..9341197 --- /dev/null +++ b/weathers/rain.lua @@ -0,0 +1,30 @@ +local name = weather_mod.modname .. ":rain" + +local weather = { + priority = 10, + spawn_puddles = true, + wetten_farmland = true, + sound = "weather_rain1" +} + +weather.particles = { + min_pos = {x=-9, y=7, z=-9}, + max_pos = {x= 9, y=7, z= 9}, + falling_speed=10, + amount=20, + exptime=0.8, + size=25, + texture="weather_rain.png" +} + +weather.clouds = { + density = 0.5, + color = "#a4a0b6e5" +} + +weather.conditions = { + min_heat = 30, + min_humidity = 40 +} + +weather_mod.register_weather(name, weather) diff --git a/weathers/rainstorm.lua b/weathers/rainstorm.lua new file mode 100644 index 0000000..207de3e --- /dev/null +++ b/weathers/rainstorm.lua @@ -0,0 +1,33 @@ +local name = weather_mod.modname .. ":rainstorm" + +local weather = { + priority = 30, + damage = true, + spawn_puddles = true, + wetten_farmland = true, + lightning = true, + sound = "weather_rain2" +} + +weather.particles = { + min_pos = {x=-9, y=7, z=-9}, + max_pos = {x= 9, y=7, z= 9}, + falling_speed=10, + amount=25, + exptime=0.8, + size=25, + texture="weather_rain.png" +} + +weather.clouds = { + density = 0.7, + color = "#a4a0b6f5" +} + +weather.conditions = { + min_heat = 30, + min_humidity = 60, + min_windspeed = 5 +} + +weather_mod.register_weather(name, weather) diff --git a/weathers/sandstorm.lua b/weathers/sandstorm.lua new file mode 100644 index 0000000..6d55153 --- /dev/null +++ b/weathers/sandstorm.lua @@ -0,0 +1,30 @@ +local name = weather_mod.modname .. ":sandstorm" + +local weather = { + priority = 50, + damage = true, + sound = "weather_wind" +} + +weather.particles = { + min_pos = {x=-9, y=-5, z=-9}, + max_pos = {x= 9, y= 5, z= 9}, + falling_speed=1, + amount=40, + exptime=0.8, + size=15, + texture="weather_sand.png" +} + +weather.clouds = { + density = 0.3, + color = "#a4a0b685" +} + +weather.conditions = { + min_heat = 50, + max_humidity = 25, + min_windspeed = 6 +} + +weather_mod.register_weather(name, weather) diff --git a/weathers/snow.lua b/weathers/snow.lua new file mode 100644 index 0000000..ab7a1a8 --- /dev/null +++ b/weathers/snow.lua @@ -0,0 +1,32 @@ +local name = weather_mod.modname .. ":snow" + +local weather = { + priority = 20, + spawn_snow = true +} + +weather.particles = { + min_pos = {x=-20, y= 3, z=-20}, + max_pos = {x= 20, y=12, z= 20}, + falling_speed=1, + amount=50, + exptime=15, + size=1, + textures = {} +} + +for i = 1,12,1 do + weather.particles.textures[i] = "weather_snowflake" .. i .. ".png" +end + +weather.clouds = { + density = 0.5, + color = "#a4a0b6e5" +} + +weather.conditions = { + max_heat = 30, + min_humidity = 40 +} + +weather_mod.register_weather(name, weather) diff --git a/weathers/snowstorm.lua b/weathers/snowstorm.lua new file mode 100644 index 0000000..4357ef7 --- /dev/null +++ b/weathers/snowstorm.lua @@ -0,0 +1,36 @@ +local name = weather_mod.modname .. ":snowstorm" + +local weather = { + priority = 40, + damage = true, + lightning = true, + spawn_snow = true, + sound = "weather_wind" +} + +weather.particles = { + min_pos = {x=-9, y=-5, z=-9}, + max_pos = {x= 9, y= 5, z= 9}, + falling_speed=1.5, + amount=70, + exptime=6, + size=1, + textures = {} +} + +for i = 1,12,1 do + weather.particles.textures[i] = "weather_snowflake" .. i .. ".png" +end + +weather.clouds = { + density = 0.7, + color = "#a4a0b6f5" +} + +weather.conditions = { + max_heat = 30, + min_humidity = 60, + min_windspeed = 5 +} + +weather_mod.register_weather(name, weather)