1
0
mirror of https://github.com/Splizard/minetest-mod-snow.git synced 2024-12-27 15:10:20 +01:00

Replace falling_snow with paramat's functional snowdrift mechanics.

This commit is contained in:
Quentin Quaadgras 2018-04-23 22:28:21 +12:00
parent a624a6fabe
commit ee3b12c07d
15 changed files with 230 additions and 284 deletions

View File

@ -75,7 +75,7 @@ dofile(srcpath.."falling_snow.lua")
local is_uneven
--This function places snow checking at the same time for snow level and increasing as needed.
--This also takes into account sourrounding snow and makes snow even.
function snow.place(pos)
function snow.place(pos, disablesound)
local node = minetest.get_node_or_nil(pos)
--Oops, maybe there is no node?
@ -89,17 +89,23 @@ function snow.place(pos)
if level < 63 then
if minetest.get_item_group(minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name, "leafdecay") == 0
and not is_uneven(pos) then
if not disablesound then
minetest.sound_play("default_snow_footstep", {pos=pos})
end
minetest.add_node_level(pos, 7)
end
elseif level == 63 then
local p = minetest.find_node_near(pos, 10, "default:dirt_with_grass")
if p
and minetest.get_node_light(p, 0.5) == 15 then
if not disablesound then
minetest.sound_play("default_grass_footstep", {pos=pos})
end
minetest.place_node({x=pos.x, y=pos.y+1, z=pos.z}, {name="default:snow"})
else
if not disablesound then
minetest.sound_play("default_snow_footstep", {pos=pos})
end
minetest.add_node(pos, {name="default:snowblock"})
end
end
@ -111,7 +117,7 @@ function snow.place(pos)
or drawtype == "allfaces_optional" then
pos.y = pos.y+1
local sound = data.sounds
if sound then
if sound and not disablesound then
sound = sound.footstep
if sound then
minetest.sound_play(sound.name, {pos=pos, gain=sound.gain})

View File

@ -1,3 +1,40 @@
License of media (snowdrift are from paramat)
---------------------------
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
You are free to:
Share — copy and redistribute the material in any medium or format.
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
Attribution — You must give appropriate credit, provide a link to the license, and
indicate if changes were made. You may do so in any reasonable manner, but not in any way
that suggests the licensor endorses you or your use.
ShareAlike — If you remix, transform, or build upon the material, you must distribute
your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that
legally restrict others from doing anything the license permits.
Notices:
You do not have to comply with the license for elements of the material in the public
domain or where your use is permitted by an applicable exception or limitation.
No warranties are given. The license may not give you all of the permissions necessary
for your intended use. For example, other rights such as publicity, privacy, or moral
rights may limit how you use the material.
For more details:
http://creativecommons.org/licenses/by-sa/3.0/
License of source code and other textures.
----------------------
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

View File

@ -1,202 +1,6 @@
--[[
--=================
--======================================
LazyJ's Fork of Splizard's "Snow" Mod
by LazyJ
version: Umpteen and 7/5ths something or another.
2014_04_12
--======================================
--=================
-- Parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
THE LIST OF CHANGES I'VE MADE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Falling snow would destroy nodes it deposited snow on. I figured out that if
I switched the 'snow.place' with 'minetest.place_node' and increased the
y position by 2, then the nodes were nolonger destroyed and the snow
would start to pile up.
~~~~~~
TODO
~~~~~~
* Add code to prevent snowfall from depositing snow on or
near torches and lava.
* Add code to prevent snowfall from depositing snow on
'walkable = false' defined nodes.
both are already fixed -- Hybrid Dog
--]]
--=============================================================
-- CODE STUFF
--=============================================================
local weather_legacy
local worldpath = minetest.get_worldpath()
local read_weather_legacy = function ()
local file = io.open(worldpath.."/weather_v6", "r")
if not file then return end
local readweather = file:read()
file:close()
return readweather
end
--Weather for legacy versions of minetest.
local save_weather_legacy = function ()
local file = io.open(worldpath.."/weather_v6", "w+")
file:write(weather_legacy)
file:close()
end
weather_legacy = read_weather_legacy() or ""
local function leg_step()
if weather_legacy == "snow" then
if math.random(1000) == 1 then
weather_legacy = "none"
save_weather_legacy()
end
elseif math.random(5000) == 2 then
weather_legacy = "snow"
save_weather_legacy()
end
minetest.after(2, leg_step)
end
minetest.after(4, leg_step)
local function infolog(msg)
minetest.log("info", "[snow] falling_snow: "..msg)
end
-- copied from meru mod
local SEEDDIFF3 = 9130 -- 9130 -- Values should match minetest mapgen desert perlin.
local OCTAVES3 = 3 -- 3
local PERSISTENCE3 = 0.5 -- 0.5
local SCALE3 = 250 -- 250
-- cache perlin noise tests
local perlin_scale, rarity
local cold_perl_values = {}
setmetatable(cold_perl_values, {__mode = "kv"})
local function cold_perlin_test(x, y)
if not cold_perl_values[y] then
cold_perl_values[y] = {}
setmetatable(cold_perl_values[y], {__mode = "kv"})
end
local v = cold_perl_values[y][x]
if v ~= nil then
return v
end
if not rarity then
rarity = snow.mapgen.smooth_rarity_min
perlin_scale = snow.mapgen.perlin_scale
end
v = minetest.get_perlin(112,3, 0.5, perlin_scale):get2d({x=x, y=y}) >= rarity
local em = ""
if type(x) ~= "number" then
em = em.. "x no number but "..type(x).." "
elseif x%1 ~= 0 then
em = em.. "x no integer but "..x.." "
end
if type(y) ~= "number" then
em = em.. "y no number but "..type(y).." "
elseif y%1 ~= 0 then
em = em.. "y no integer but "..y.." "
end
if em ~= "" then
error(em)
end
if cold_perl_values[y] then
cold_perl_values[y][x] = v
end
return v
end
-- disable falling snow in desert
local desert_perl_values = {}
setmetatable(desert_perl_values, {__mode = "kv"})
local function is_desert(x, y)
if not desert_perl_values[y] then
desert_perl_values[y] = {}
setmetatable(desert_perl_values[y], {__mode = "kv"})
end
local v = desert_perl_values[y][x]
if v ~= nil then
return v
end
-- Offsets must match minetest mapgen desert perlin.
-- Smooth transition 0.35 to 0.45.
v = minetest.get_perlin(SEEDDIFF3, OCTAVES3, PERSISTENCE3, SCALE3):get2d({x=x+150,y=y+50}) <= 0.35
desert_perl_values[y][x] = v
return v
end
--Get snow at position.
local function get_snow(pos)
return weather_legacy == "snow" --Legacy support.
and cold_perlin_test(pos.x, pos.z)
and not is_desert(pos.x, pos.z)
end
local addvectors = vector.add
--Returns a random position between minp and maxp.
-- TODO: make a fload random position
local function randpos(minp, maxp)
local x,z
if minp.x > maxp.x then
x = math.random(maxp.x,minp.x)
else
x = math.random(minp.x,maxp.x)
end
if minp.z > maxp.z then
z = math.random(maxp.z,minp.z)
else
z = math.random(minp.z,maxp.z)
end
return {x=x,y=minp.y,z=z}
end
local default_snow_particle = {
amount = 3,
time = 0.5,
exptime = 5,
size = 50,
collisiondetection = false,
vertical = false,
}
local function get_snow_particledef(data)
for n,i in pairs(default_snow_particle) do
data[n] = data[n] or i
end
for _,i in pairs({"vel", "acc", "exptime", "size"}) do
data["min"..i] = data[i]
data["max"..i] = data[i]
end
data.texture = "weather_snow.png^[transform"..math.random(0,7)
return data
end
local function snow_fall(pos, player, animate)
function snow_fall(pos, player, animate)
local ground_y = nil
for y=pos.y+10,pos.y+20,1 do
local n = minetest.get_node({x=pos.x,y=y,z=pos.z}).name
@ -217,99 +21,198 @@ local function snow_fall(pos, player, animate)
pos = {x=pos.x, y=ground_y, z=pos.z}
if not get_snow(pos) then
return
end
if animate then
local spos = {x=pos.x, y=ground_y+10, z=pos.z}
minetest.add_particlespawner(get_snow_particledef({
minpos = addvectors(spos, {x=-9, y=3, z=-9}),
maxpos = addvectors(spos, {x= 9, y=5, z= 9}),
vel = {x=0, y=-1, z=-1},
acc = {x=0, y=0, z=0},
playername = player:get_player_name()
}))
end
snow.place(pos, true)
--minetest.place_node({x=pos.x, y=pos.y+2, z=pos.z}, {name="default:snow"}) -- LazyJ
end
-- Snow
local lighter_snowfall = snow.lighter_snowfall
local function calc_snowfall()
for _, player in pairs(minetest.get_connected_players()) do
local ppos = vector.round(player:getpos())
local YLIMIT = 1 -- Set to world's water level
-- Particles are timed to disappear at this y
-- Particles do not spawn when player's head is below this y
local PRECSPR = 6 -- Time scale for precipitation variation in minutes
local PRECOFF = -0.4 -- Precipitation offset, higher = rains more often
local GSCYCLE = 0.5 -- Globalstep cycle (seconds)
local FLAKES = 32 -- Snowflakes per cycle
local DROPS = 128 -- Raindrops per cycle
local RAINGAIN = 0.2 -- Rain sound volume
local COLLIDE = false -- Whether particles collide with nodes
local NISVAL = 39 -- Clouds RGB value at night
local DASVAL = 175 -- Clouds RGB value in daytime
-- Make sure player is not in a cave/house...
if get_snow(ppos)
and minetest.get_node_light(ppos, 0.5) == 15 then
local animate
if not lighter_snowfall then
local vel = {x=0, y=-1, z=-1}
local acc = {x=0, y=0, z=0}
minetest.add_particlespawner(get_snow_particledef({
amount = 5,
minpos = addvectors(ppos, {x=-9, y=3, z=-9}),
maxpos = addvectors(ppos, {x= 9, y=5, z= 9}),
vel = vel,
acc = acc,
size = 25,
playername = player:get_player_name()
}))
local np_prec = {
offset = 0,
scale = 1,
spread = {x = PRECSPR, y = PRECSPR, z = PRECSPR},
seed = 813,
octaves = 1,
persist = 0,
lacunarity = 2.0,
--flags = ""
}
minetest.add_particlespawner(get_snow_particledef({
amount = 4,
minpos = addvectors(ppos, {x=-5, y=3.2, z=-5}),
maxpos = addvectors(ppos, {x= 5, y=1.6, z= 5}),
vel = vel,
acc = acc,
exptime = 4,
size = 25,
playername = player:get_player_name()
}))
-- These 2 must match biome heat and humidity noise parameters for a world
animate = false
else
animate = true
end
local np_temp = {
offset = 50,
scale = 50,
spread = {x = 1000, y = 1000, z = 1000},
seed = 5349,
octaves = 3,
persist = 0.5,
lacunarity = 2.0,
--flags = ""
}
if math.random(1,5) == 4 then
snow_fall(
randpos(
addvectors(ppos, {x=-20, y=0, z=-20}),
addvectors(ppos, {x= 20, y=0, z= 20})
),
player,
animate
)
end
end
end
end
local np_humid = {
offset = 50,
scale = 50,
spread = {x = 1000, y = 1000, z = 1000},
seed = 842,
octaves = 3,
persist = 0.5,
lacunarity = 2.0,
--flags = ""
}
local step_func
minetest.register_globalstep(function()
step_func()
end)
-- Stuff
local difsval = DASVAL - NISVAL
local grad = 14 / 95
local yint = 1496 / 95
-- Initialise noise objects to nil
local nobj_temp = nil
local nobj_humid = nil
local nobj_prec = nil
-- Globalstep function
local timer = 0
if snow.enable_snowfall then
step_func = calc_snowfall
infolog("step function set to calc_snowfall")
else
step_func = function() end
infolog("step function set to empty function")
end
snow.register_on_configuring(function(name, v)
if name == "enable_snowfall" then
if v then
step_func = calc_snowfall
infolog("step function set to calc_snowfall")
else
step_func = function() end
infolog("step function set to empty function")
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer < GSCYCLE then
return
end
elseif name == "lighter_snowfall" then
lighter_snowfall = v
end
end)
timer = 0
for _, player in ipairs(minetest.get_connected_players()) do
local player_name = player:get_player_name()
local ppos = player:getpos()
local pposy = math.floor(ppos.y) + 2 -- Precipitation when swimming
if pposy >= YLIMIT - 2 then
local pposx = math.floor(ppos.x)
local pposz = math.floor(ppos.z)
local ppos = {x = pposx, y = pposy, z = pposz}
local nobj_temp = nobj_temp or minetest.get_perlin(np_temp)
local nobj_humid = nobj_humid or minetest.get_perlin(np_humid)
local nobj_prec = nobj_prec or minetest.get_perlin(np_prec)
local nval_temp = nobj_temp:get2d({x = pposx, y = pposz})
local nval_humid = nobj_humid:get2d({x = pposx, y = pposz})
local nval_prec = nobj_prec:get2d({x = os.clock() / 60, y = 0})
-- Biome system: Frozen biomes below heat 35,
-- deserts below line 14 * t - 95 * h = -1496
-- h = (14 * t + 1496) / 95
-- h = 14/95 * t + 1496/95
-- where 14/95 is gradient and 1496/95 is y intersection
-- h - 14/95 t = 1496/95 y intersection
-- so area above line is
-- h - 14/95 t > 1496/95
local freeze = nval_temp < 35
local precip = nval_prec < (nval_humid - 50) / 50 + PRECOFF and
nval_humid - grad * nval_temp > yint
if snow.debug then
precip = true
end
-- Check if player is outside
local outside = minetest.get_node_light(ppos, 0.5) == 15
-- Occasionally reset player sky
if math.random() < 0.1 then
if precip then
-- Set overcast sky
local sval
local time = minetest.get_timeofday()
if time >= 0.5 then
time = 1 - time
end
-- Sky brightness transitions:
-- First transition (24000 -) 4500, (1 -) 0.1875
-- Last transition (24000 -) 5750, (1 -) 0.2396
if time <= 0.1875 then
sval = NISVAL
elseif time >= 0.2396 then
sval = DASVAL
else
sval = math.floor(NISVAL +
((time - 0.1875) / 0.0521) * difsval)
end
-- Set sky to overcast bluish-grey
player:set_sky(
{r = sval, g = sval, b = sval + 16, a = 255},
"plain",
{}
)
else
-- Reset sky to normal
player:set_sky({}, "regular", {})
end
end
if precip and outside then
-- Precipitation
if freeze then
-- Snowfall
local extime = math.min((pposy + 12 - YLIMIT) / 2, 9)
local x, y, z = pposx - 24 + math.random(0, 48), pposy + 12, pposz - 24 + math.random(0, 48)
if not snow.lighter_snowfall then
snow_fall({
x = x,
y = y,
z = z
}, true)
end
for flake = 1, FLAKES do
x, y, z = pposx - 24 + math.random(0, 48), pposy + 12, pposz - 24 + math.random(0, 48)
minetest.add_particle({
pos = {
x = x,
y = y,
z = z
},
velocity = {
x = (-20 + math.random(0, 40)) / 100,
y = -2.0,
z = (-20 + math.random(0, 40)) / 100
},
acceleration = {x = 0, y = 0, z = 0},
expirationtime = extime,
size = 2.8,
collisiondetection = COLLIDE,
collision_removal = true,
vertical = false,
texture = "snowdrift_snowflake" ..
math.random(1, 12) .. ".png",
playername = player:get_player_name()
})
end
end
end
end
end
end)
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B