mymonths/abms.lua

263 lines
9.1 KiB
Lua

local function level_snow(pos, node, depth)
local sides = {
{x=pos.x - 1, y=pos.y, z=pos.z},
{x=pos.x - 1, y=pos.y, z=pos.z + 1},
{x=pos.x, y=pos.y, z=pos.z + 1},
{x=pos.x + 1, y=pos.y, z=pos.z + 1},
{x=pos.x + 1, y=pos.y, z=pos.z},
{x=pos.x + 1, y=pos.y, z=pos.z - 1},
{x=pos.x, y=pos.y, z=pos.z - 1},
{x=pos.x - 1, y=pos.y, z=pos.z - 1},
}
local snow_level = {}
snow_level["air"] = {"mymonths:snow_cover_1", 0}
snow_level["default:snow"] = {"mymonths:snow_cover_3", 2}
snow_level["mymonths:snow_cover_1"] = {"mymonths:snow_cover_2", 1}
snow_level["mymonths:snow_cover_2"] = {"mymonths:snow_cover_3", 2}
snow_level["mymonths:snow_cover_3"] = {"mymonths:snow_cover_4", 3}
snow_level["mymonths:snow_cover_4"] = {"mymonths:snow_cover_5", 4}
snow_level["mymonths:snow_cover_5"] = {"default:snowblock", 5}
for i = 1,8 do
local temp_node = minetest.get_node_or_nil(sides[i])
-- check if node exsists and block is solid
if temp_node ~= nil and snow_level[temp_node.name] ~= nil then
-- check the difference in snow heights
if snow_level[node.name][2] - snow_level[temp_node.name][2] > 2 then
-- shift the node down till it can be filled
if temp_node.name == "air" then
while minetest.get_node_or_nil({x=sides[i].x, y=sides[i].y - 1, z=sides[i].z}) ~= nil and
snow_level[minetest.get_node_or_nil({x=sides[i].x, y=sides[i].y - 1, z=sides[i].z}).name] ~= nil do
sides[i].y = sides[i].y - 1
end
if depth > 4 or level_snow(sides[i], temp_node, depth + 1) then
temp_node = minetest.get_node_or_nil(sides[i])
end
end
minetest.set_node(sides[i], {name = snow_level[temp_node.name][1]})
return false
end
end
end
return true
end
local function is_inside(pos)
if minetest.get_node_light({x=pos.x,y=pos.y+1,z=pos.z}, 0.5) ~= 15 then
return true
end
local temp_node = minetest.get_node_or_nil({x=pos.x,y=pos.y+1,z=pos.z})
for i = 2,50 do
if temp_node ~= nil and temp_node.name ~= "air" then
return true
end
temp_node = minetest.get_node_or_nil({x=pos.x,y=pos.y+i,z=pos.z})
end
return false
end
local function get_melt_prob(pos)
local list1 = minetest.find_nodes_in_area({x=pos.x-3,y=pos.y-2,z=pos.z-3},
{x=pos.x+3,y=pos.y+1,z=pos.z+3},{"default:ice", "default:snowblock"})
local list2 = minetest.find_nodes_in_area({x=pos.x-3,y=pos.y-2,z=pos.z-3},
{x=pos.x+3,y=pos.y+1,z=pos.z+3},{"mymonths:snow_cover_5",
"mymonths:snow_cover_4","mymonths:snow_cover_3","mymonths:snow_cover_2","mymonths:snow_cover_1"})
local list3 = minetest.find_nodes_in_area({x=pos.x-3,y=pos.y-2,z=pos.z-3},
{x=pos.x+3,y=pos.y+1,z=pos.z+3},{"default:dirt_with_snow", "default:pine_tree"})
-- list1 is snow blocks and ice, list 2 is snow cover nodes, list3 is snow dirt and pine trees
local count = 2.25 * table.getn(list1) + table.getn(list2) + 2 * table.getn(list3)
local prob = 1 - count/196
prob = math.max(tonumber(string.format("%.2f", prob * 10)), 0.01)
prob = 1 / (prob / 200)
prob = math.min(tonumber(string.format("%04d", prob)), 1000)
return prob
end
--Places Snow on ground
if mymonths.snow_on_ground == true then
minetest.register_abm({
nodenames = {"group:leaves", "group:soil", "default:snowblock"},
neighbors = {"air"},
interval = 8,
chance = 20,
action = function (pos, node)
if mymonths.weather == "snow" or mymonths.weather == "snowstorm" then
local biome_jungle = minetest.find_node_near(pos, 5, "default:jungletree", "default:junglegrass")
pos.y = pos.y + 1 -- check above node
local na = minetest.get_node(pos)
if biome_jungle == nil then
if not is_inside(pos) and na.name == "air" then
minetest.set_node(pos, {name = "mymonths:snow_cover_1"})
end
end
end
end
})
--Replace grass and flowers with snow
minetest.register_abm({
nodenames = {"group:flora", "mymonths:puddle", "group:plant"},
neighbors = {"air"},
interval = 8,
chance = 20,
action = function (pos, node)
if mymonths.weather == "snow" or mymonths.weather == "snowstorm" then
local biome_jungle = minetest.find_node_near(pos, 5, "default:jungletree","default:junglegrass")
if biome_jungle == nil then
if not is_inside(pos) then
minetest.set_node(pos, {name="mymonths:snow_cover_1"})
end
end
end
end
})
-- Changes snow to larger snow
minetest.register_abm({
nodenames = {"mymonths:snow_cover_1", "mymonths:snow_cover_2", "mymonths:snow_cover_3", "mymonths:snow_cover_4", "mymonths:snow_cover_5", "default:snow"},
neighbors = {"group:soil", "default:snowblock"},
interval = 20,
chance = 40,
action = function (pos, node)
if mymonths.weather2 == "snow" or mymonths.weather2 == "snowstorm" then
if mymonths.weather2 == "snow" and math.random(1, 4) ~= 1 then
return
end
if node.name == "mymonths:snow_cover_1" then
minetest.set_node(pos, {name = "mymonths:snow_cover_2"})
elseif node.name == "mymonths:snow_cover_2" or node.name == "default:snow" then
minetest.set_node(pos, {name = "mymonths:snow_cover_3"})
elseif node.name == "mymonths:snow_cover_3" then
minetest.set_node(pos, {name = "mymonths:snow_cover_4"})
elseif node.name == "mymonths:snow_cover_4" then
minetest.set_node(pos, {name = "mymonths:snow_cover_5"})
elseif node.name == "mymonths:snow_cover_5" then
local depth = 2
local snow_biome = minetest.find_node_near(pos, 5, {"default:ice"})
-- checks the number of snow blocks below to determine if snow is too deep
local count = 0
for i = 1, depth do
local new_pos_y = pos.y - i
local temp_node = minetest.get_node_or_nil({x=pos.x, y=new_pos_y, z=pos.z})
if temp_node ~= nil then
if temp_node.name == "default:snowblock" then
count = count + 1
end
end
end
if level_snow(pos, node, 0) and (count ~= depth or snow_biome) then
minetest.set_node(pos, {name = "default:snowblock"})
end
end
end
end
})
-- Snow Melting
minetest.register_abm({
nodenames = {"mymonths:snow_cover_1", "mymonths:snow_cover_2", "mymonths:snow_cover_3", "mymonths:snow_cover_4", "mymonths:snow_cover_5", "default:snowblock", "default:snow"},
neighbors = {"air"},
interval = 10,
chance = 1,
action = function (pos, node)
if mymonths.month_counter == 12 or mymonths.month_counter == 1 or mymonths.month_counter == 2 then
return
end
local melt_prob = get_melt_prob(pos)
if melt_prob == 1000 then
return
end
if math.random(1, melt_prob) == 1 then
-- check if there is any blocks above it
while minetest.get_node_or_nil({x=pos.x, y=pos.y + 1, z=pos.z}) and
minetest.get_node_or_nil({x=pos.x, y=pos.y + 1, z=pos.z}).name ~= "air" do
pos.y = pos.y + 1
node = minetest.get_node_or_nil(pos)
end
if node.name == "mymonths:snow_cover_2" or node.name == "default:snow" then
minetest.set_node(pos, {name = "mymonths:snow_cover_1"})
elseif node.name == "mymonths:snow_cover_3" then
minetest.set_node(pos, {name = "mymonths:snow_cover_2"})
elseif node.name == "mymonths:snow_cover_4" then
minetest.set_node(pos, {name = "mymonths:snow_cover_3"})
elseif node.name == "mymonths:snow_cover_5" then
minetest.set_node(pos, {name = "mymonths:snow_cover_4"})
elseif node.name == "default:snowblock" then
minetest.set_node(pos, {name = "mymonths:snow_cover_5"})
elseif node.name == "mymonths:snow_cover_1" then
local nu = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
if nu.name == "default:dirt_with_grass" or nu.name == "default:dirt" then
minetest.set_node(pos, {name = "mymonths:puddle"})
else
minetest.remove_node(pos)
end
end
end
end
})
end -- END IF
if mymonths.use_puddles == true then
-- Makes Puddles when raining
minetest.register_abm({
nodenames = {"group:soil"},
neighbors = {"default:air"},
interval = 10,
chance = 50,
action = function (pos, node)
if mymonths.weather == "rain" then
-- return if puddle found nearby
if minetest.find_node_near(pos, 20, "mymonths:puddle") then
return
end
pos.y = pos.y + 1
-- otherwise place puddle in empty space
if minetest.get_node_light(pos, 0.5) == 15
and minetest.get_node(pos).name == "air" then
minetest.set_node(pos, {name = "mymonths:puddle"})
end
end
end
})
-- Makes puddles dry up when not raining
minetest.register_abm({
nodenames = {"mymonths:puddle"},
neighbors = {"air"},
interval = 5,
chance = 5,
action = function (pos, node)
if mymonths.weather == "clear" then
minetest.remove_node(pos)
elseif mymonths.weather == "snow"
or mymonths.weather == "snowstorm" then
minetest.set_node(pos, {name = "mymonths:snow_cover_1"})
end
end
})
end -- END IF