├── depends.txt ├── sounds └── snowdrift_rain.ogg ├── textures ├── snowdrift_raindrop.png ├── snowdrift_snowflake1.png ├── snowdrift_snowflake10.png ├── snowdrift_snowflake11.png ├── snowdrift_snowflake12.png ├── snowdrift_snowflake2.png ├── snowdrift_snowflake3.png ├── snowdrift_snowflake4.png ├── snowdrift_snowflake5.png ├── snowdrift_snowflake6.png ├── snowdrift_snowflake7.png ├── snowdrift_snowflake8.png └── snowdrift_snowflake9.png ├── README.txt ├── license.txt └── init.lua /depends.txt: -------------------------------------------------------------------------------- 1 | default 2 | -------------------------------------------------------------------------------- /sounds/snowdrift_rain.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/sounds/snowdrift_rain.ogg -------------------------------------------------------------------------------- /textures/snowdrift_raindrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_raindrop.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake1.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake10.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake11.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake12.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake2.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake3.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake4.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake5.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake6.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake7.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake8.png -------------------------------------------------------------------------------- /textures/snowdrift_snowflake9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paramat/snowdrift/HEAD/textures/snowdrift_snowflake9.png -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | snowdrift 0.6.4 by paramat. 2 | For Minetest 0.4.16 and later. Compatible with Minetest 5.0.0. 3 | Depends: default. 4 | 5 | Licenses 6 | -------- 7 | Source code: MIT by paramat. 8 | Media: 9 | Textures CC BY-SA (3.0) by paramat. 10 | Sounds CC BY (3.0) by inchadney. 11 | http://freesound.org/people/inchadney/sounds/58835/ 12 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | License of source code 2 | ---------------------- 3 | 4 | The MIT License (MIT) 5 | Copyright (C) 2017 paramat 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, merge, 10 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 17 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 18 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 19 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | 23 | For more details: 24 | https://opensource.org/licenses/MIT 25 | 26 | 27 | License of media (textures) 28 | --------------------------- 29 | 30 | Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) 31 | Copyright (C) 2017 paramat 32 | 33 | You are free to: 34 | Share — copy and redistribute the material in any medium or format. 35 | Adapt — remix, transform, and build upon the material for any purpose, even commercially. 36 | The licensor cannot revoke these freedoms as long as you follow the license terms. 37 | 38 | Under the following terms: 39 | 40 | Attribution — You must give appropriate credit, provide a link to the license, and 41 | indicate if changes were made. You may do so in any reasonable manner, but not in any way 42 | that suggests the licensor endorses you or your use. 43 | 44 | ShareAlike — If you remix, transform, or build upon the material, you must distribute 45 | your contributions under the same license as the original. 46 | 47 | No additional restrictions — You may not apply legal terms or technological measures that 48 | legally restrict others from doing anything the license permits. 49 | 50 | Notices: 51 | 52 | You do not have to comply with the license for elements of the material in the public 53 | domain or where your use is permitted by an applicable exception or limitation. 54 | No warranties are given. The license may not give you all of the permissions necessary 55 | for your intended use. For example, other rights such as publicity, privacy, or moral 56 | rights may limit how you use the material. 57 | 58 | For more details: 59 | http://creativecommons.org/licenses/by-sa/3.0/ 60 | 61 | 62 | License of media (sounds) 63 | ------------------------- 64 | 65 | Attribution 3.0 Unported (CC BY 3.0) 66 | Copyright (C) 2008 inchadney 67 | 68 | You are free to: 69 | Share — copy and redistribute the material in any medium or format. 70 | Adapt — remix, transform, and build upon the material for any purpose, even commercially. 71 | The licensor cannot revoke these freedoms as long as you follow the license terms. 72 | 73 | Under the following terms: 74 | 75 | Attribution — You must give appropriate credit, provide a link to the license, and 76 | indicate if changes were made. You may do so in any reasonable manner, but not in any way 77 | that suggests the licensor endorses you or your use. 78 | 79 | No additional restrictions — You may not apply legal terms or technological measures that 80 | legally restrict others from doing anything the license permits. 81 | 82 | Notices: 83 | 84 | You do not have to comply with the license for elements of the material in the public 85 | domain or where your use is permitted by an applicable exception or limitation. 86 | No warranties are given. The license may not give you all of the permissions necessary 87 | for your intended use. For example, other rights such as publicity, privacy, or moral 88 | rights may limit how you use the material. 89 | 90 | For more details: 91 | http://creativecommons.org/licenses/by/3.0/ 92 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | -- Parameters 2 | 3 | local YWATER = 1 -- Normally set this to world's water level 4 | -- Particles are timed to disappear at this y 5 | -- Particles are not spawned for players below this y 6 | -- Rain sound is not played for players below this y 7 | local YMIN = -48 -- Normally set this to deepest ocean 8 | local YMAX = 120 -- Normally set this to cloud level 9 | -- Weather does not occur for players outside this y range 10 | local PRECTIM = 300 -- Precipitation noise 'spread' 11 | -- Time scale for precipitation variation, in seconds 12 | local PRECTHR = 0.2 -- Precipitation noise threshold, -1 to 1: 13 | -- -1 = precipitation all the time 14 | -- 0 = precipitation half the time 15 | -- 1 = no precipitation 16 | local FLAKLPOS = 32 -- Snowflake light-tested positions per 0.5s cycle 17 | -- Maximum number of snowflakes spawned per 0.5s 18 | local DROPLPOS = 64 -- Raindrop light-tested positions per 0.5s cycle 19 | local DROPPPOS = 2 -- Number of raindrops spawned per light-tested position 20 | local RAINGAIN = 0.2 -- Rain sound volume 21 | local NISVAL = 39 -- Overcast sky RGB value at night (brightness) 22 | local DASVAL = 159 -- Overcast sky RGB value in daytime (brightness) 23 | local FLAKRAD = 16 -- Radius in which flakes are created 24 | local DROPRAD = 16 -- Radius in which drops are created 25 | 26 | -- Precipitation noise 27 | 28 | local np_prec = { 29 | offset = 0, 30 | scale = 1, 31 | spread = {x = PRECTIM, y = PRECTIM, z = PRECTIM}, 32 | seed = 813, 33 | octaves = 1, 34 | persist = 0, 35 | lacunarity = 2.0, 36 | flags = "defaults" 37 | } 38 | 39 | -- These 2 must match biome heat and humidity noise parameters for a world 40 | 41 | local np_temp = { 42 | offset = 50, 43 | scale = 50, 44 | spread = {x = 1000, y = 1000, z = 1000}, 45 | seed = 5349, 46 | octaves = 3, 47 | persist = 0.5, 48 | lacunarity = 2.0, 49 | flags = "defaults" 50 | } 51 | 52 | local np_humid = { 53 | offset = 50, 54 | scale = 50, 55 | spread = {x = 1000, y = 1000, z = 1000}, 56 | seed = 842, 57 | octaves = 3, 58 | persist = 0.5, 59 | lacunarity = 2.0, 60 | flags = "defaults" 61 | } 62 | 63 | -- End parameters 64 | 65 | 66 | -- Some stuff 67 | 68 | local difsval = DASVAL - NISVAL 69 | local grad = 14 / 95 70 | local yint = 1496 / 95 71 | 72 | 73 | -- Initialise noise objects to nil 74 | 75 | local nobj_temp = nil 76 | local nobj_humid = nil 77 | local nobj_prec = nil 78 | 79 | 80 | -- Player tables 81 | 82 | local handles = {} 83 | local skybox = {} -- true/false. To not turn off skyboxes of other mods 84 | 85 | 86 | -- Globalstep function 87 | 88 | local os_time_0 = os.time() 89 | local t_offset = math.random(0, 300000) 90 | 91 | local timer = 0 92 | 93 | minetest.register_globalstep(function(dtime) 94 | timer = timer + dtime 95 | if timer < 0.5 then 96 | return 97 | end 98 | 99 | timer = 0 100 | 101 | for _, player in ipairs(minetest.get_connected_players()) do 102 | local player_name = player:get_player_name() 103 | local ppos = player:getpos() 104 | -- Point just above player head, to ensure precipitation when swimming 105 | local pposy = math.floor(ppos.y) + 2 106 | if pposy >= YMIN and pposy <= YMAX then 107 | local pposx = math.floor(ppos.x) 108 | local pposz = math.floor(ppos.z) 109 | local ppos = {x = pposx, y = pposy, z = pposz} 110 | 111 | -- Heat, humidity and precipitation noises 112 | 113 | -- Time in seconds. 114 | -- Add the per-server-session random time offset to avoid identical behaviour 115 | -- each server session. 116 | local time = os.difftime(os.time(), os_time_0) - t_offset 117 | 118 | local nobj_temp = nobj_temp or minetest.get_perlin(np_temp) 119 | local nobj_humid = nobj_humid or minetest.get_perlin(np_humid) 120 | local nobj_prec = nobj_prec or minetest.get_perlin(np_prec) 121 | 122 | local nval_temp = nobj_temp:get2d({x = pposx, y = pposz}) 123 | local nval_humid = nobj_humid:get2d({x = pposx, y = pposz}) 124 | local nval_prec = nobj_prec:get2d({x = time, y = 0}) 125 | 126 | -- Default Minetest Game biome system: 127 | -- Frozen biomes below heat 35 128 | -- deserts below line 14 * t - 95 * h = -1496 129 | -- h = (14 * t + 1496) / 95 130 | -- h = 14/95 * t + 1496/95 131 | -- where 14/95 is gradient and 1496/95 is 'y-intersection' 132 | -- h - 14/95 * t = 1496/95 133 | -- so area above line is 134 | -- h - 14/95 * t > 1496/95 135 | 136 | local freeze = nval_temp < 35 137 | local precip = nval_prec > PRECTHR and 138 | nval_humid - grad * nval_temp > yint 139 | 140 | -- Set sky 141 | if precip and not skybox[player_name] then 142 | -- Set overcast sky only if normal 143 | local sval 144 | local time = minetest.get_timeofday() 145 | if time >= 0.5 then 146 | time = 1 - time 147 | end 148 | -- Sky brightness transitions: 149 | -- First transition (24000 -) 4500, (1 -) 0.1875 150 | -- Last transition (24000 -) 5750, (1 -) 0.2396 151 | if time <= 0.1875 then 152 | sval = NISVAL 153 | elseif time >= 0.2396 then 154 | sval = DASVAL 155 | else 156 | sval = math.floor(NISVAL + 157 | ((time - 0.1875) / 0.0521) * difsval) 158 | end 159 | player:set_sky({r = sval, g = sval, b = sval + 16, a = 255}, 160 | "plain", {}, false) 161 | skybox[player_name] = true 162 | elseif not precip and skybox[player_name] then 163 | -- Set normal sky only if skybox 164 | player:set_sky({}, "regular", {}, true) 165 | skybox[player_name] = nil 166 | end 167 | 168 | -- Stop looping sound. 169 | -- Stop sound if head below water level. 170 | if not precip or freeze or pposy < YWATER then 171 | if handles[player_name] then 172 | minetest.sound_stop(handles[player_name]) 173 | handles[player_name] = nil 174 | end 175 | end 176 | 177 | -- Particles and sounds. 178 | -- Only if head above water level. 179 | if precip and pposy >= YWATER then 180 | if freeze then 181 | -- Snowfall particles 182 | for lpos = 1, FLAKLPOS do 183 | local lposx = pposx - FLAKRAD + 184 | math.random(0, FLAKRAD * 2) 185 | local lposz = pposz - FLAKRAD + 186 | math.random(0, FLAKRAD * 2) 187 | if minetest.get_node_light( 188 | {x = lposx, y = pposy + 10, z = lposz}, 189 | 0.5) == 15 then 190 | -- Any position above light-tested position is also 191 | -- light level 15. 192 | -- Spawn Y randomised to avoid particles falling 193 | -- in separated layers. 194 | -- Random range = speed * cycle time 195 | local spawny = pposy + 10 + math.random(0, 10) / 10 196 | local extime = math.min((spawny - YWATER) / 2, 10) 197 | 198 | minetest.add_particle({ 199 | pos = {x = lposx, y = spawny, z = lposz}, 200 | velocity = {x = 0, y = -2.0, z = 0}, 201 | acceleration = {x = 0, y = 0, z = 0}, 202 | expirationtime = extime, 203 | size = 2.8, 204 | collisiondetection = true, 205 | collision_removal = true, 206 | vertical = false, 207 | texture = "snowdrift_snowflake" .. 208 | math.random(1, 12) .. ".png", 209 | playername = player:get_player_name() 210 | }) 211 | end 212 | end 213 | else 214 | -- Rainfall particles 215 | for lpos = 1, DROPLPOS do 216 | local lposx = pposx - DROPRAD + 217 | math.random(0, DROPRAD * 2) 218 | local lposz = pposz - DROPRAD + 219 | math.random(0, DROPRAD * 2) 220 | if minetest.get_node_light( 221 | {x = lposx, y = pposy + 10, z = lposz}, 222 | 0.5) == 15 then 223 | for drop = 1, DROPPPOS do 224 | local spawny = pposy + 10 + math.random(0, 60) / 10 225 | local extime = math.min((spawny - YWATER) / 12, 2) 226 | local spawnx = lposx - 0.4 + math.random(0, 8) / 10 227 | local spawnz = lposz - 0.4 + math.random(0, 8) / 10 228 | 229 | minetest.add_particle({ 230 | pos = {x = spawnx, y = spawny, z = spawnz}, 231 | velocity = {x = 0.0, y = -12.0, z = 0.0}, 232 | acceleration = {x = 0, y = 0, z = 0}, 233 | expirationtime = extime, 234 | size = 2.8, 235 | collisiondetection = true, 236 | collision_removal = true, 237 | vertical = true, 238 | texture = "snowdrift_raindrop.png", 239 | playername = player:get_player_name() 240 | }) 241 | end 242 | end 243 | end 244 | -- Start looping sound 245 | if not handles[player_name] then 246 | local handle = minetest.sound_play( 247 | "snowdrift_rain", 248 | { 249 | to_player = player_name, 250 | gain = RAINGAIN, 251 | loop = true, 252 | } 253 | ) 254 | if handle then 255 | handles[player_name] = handle 256 | end 257 | end 258 | end 259 | end 260 | else 261 | -- Player outside y limits. 262 | -- Stop sound if playing. 263 | if handles[player_name] then 264 | minetest.sound_stop(handles[player_name]) 265 | handles[player_name] = nil 266 | end 267 | -- Set normal sky if skybox 268 | if skybox[player_name] then 269 | player:set_sky({}, "regular", {}, true) 270 | skybox[player_name] = nil 271 | end 272 | end 273 | end 274 | end) 275 | 276 | 277 | -- On leaveplayer function 278 | 279 | minetest.register_on_leaveplayer(function(player) 280 | local player_name = player:get_player_name() 281 | -- Stop sound if playing and remove handle 282 | if handles[player_name] then 283 | minetest.sound_stop(handles[player_name]) 284 | handles[player_name] = nil 285 | end 286 | -- Remove skybox bool if necessary 287 | if skybox[player_name] then 288 | skybox[player_name] = nil 289 | end 290 | end) 291 | --------------------------------------------------------------------------------