lib_materials/lib_materials_lakes.lua

267 lines
8.3 KiB
Lua

--[[
1. We choose a random position in the same way plants are placed. That's the root for our lake.
2. From there we go lx in the x direction and lz in the z direction. That gives us a rectangle.
3. We check the sides of the rectangle for air and itterate down until the rectangle is closed.
4. Now we repeat this itteration, but search for the opposite, not for solid nodes but for air.
5. As soon as we found the lower limit, we check if the bottom is sealed. Now we have some jar.
6. Now as we made sure no water can escape we can replace all air inside the volume with water.
--]]
--lib_lakes = {}
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_lava = minetest.get_content_id("lib_materials:liquid_lava_source")
local c_water = minetest.get_content_id("lib_materials:liquid_water_source")
local c_ice = minetest.get_content_id("lib_materials:ice")
local c_murky = minetest.get_content_id("lib_materials:liquid_water_murky_source")
local c_dirty = minetest.get_content_id("lib_materials:liquid_water_dirty_source")
local c_river = minetest.get_content_id("lib_materials:liquid_water_river_source")
local c_muddy = minetest.get_content_id("lib_materials:liquid_water_river_muddy_source")
local c_quick_source = minetest.get_content_id("lib_materials:liquid_quicksand_source")
local c_quick = minetest.get_content_id("lib_materials:quicksand")
local c_mud_boil = minetest.get_content_id("lib_materials:liquid_mud_boiling_source")
local c_mud_wet = minetest.get_content_id("lib_materials:mud_wet")
local c_mud_dried = minetest.get_content_id("lib_materials:dirt_mud_dried")
local c_fluid_id
--
-- Find position
--
minetest.register_on_generated(function(minp, maxp, seed)
if maxp.y <= 1024 and minp.y >= -32 then
local perlin1 = minetest.get_perlin(318, 3, 0.6, 100)
-- Lua Voxel Machine
local vm = minetest.get_voxel_manip()
local vm_minp, vm_maxp = vm:read_from_map({x=minp.x, y=minp.y, z=minp.z-16}, {x=maxp.x+16, y=maxp.y+16, z=maxp.z+16})
local a = VoxelArea:new{MinEdge=vm_minp, MaxEdge=vm_maxp}
local data = vm:get_data()
-- Assume X and Z lengths are equal
local divlen = 32
local divs = (maxp.x-minp.x)/divlen+1;
for divx=0,divs-1 do
for divz=0,divs-1 do
local x0 = minp.x + math.floor((divx+0)*divlen)
local z0 = minp.z + math.floor((divz+0)*divlen)
local x1 = minp.x + math.floor((divx+1)*divlen)
local z1 = minp.z + math.floor((divz+1)*divlen)
-- Determine amount from perlin noise
local amount = math.floor(perlin1:get2d({x=x0, y=z0}) * 5 + 10)
-- Find random positions based on this random
local pr = PseudoRandom(seed+486)
for i=0,amount do
local x = pr:next(x0, x1)
local z = pr:next(z0, z1)
local ground_y = nil
-- Prevent from starting underground
local nn = minetest.get_node({x=x,y=maxp.y,z=z}).name
if nn ~= "air" and nn ~= "ignore" then
return
end
-- Find groundlevel
for y=maxp.y,minp.y,-1 do
local nn = minetest.get_node({x=x,y=y,z=z}).name
if nn ~= "air" and nn~= "ignore" then
--local is_leaves = minetest.registered_nodes[nn].groups.leaves
--if is_leaves == nil or is_leaves == 0 then
-- ground_y = y
-- break
--end
local is_removable
is_removable = minetest.registered_nodes[nn].groups.leaves
is_removable = minetest.registered_nodes[nn].groups.tree
is_removable = minetest.registered_nodes[nn].groups.sapling
is_removable = minetest.registered_nodes[nn].groups.plant
is_removable = minetest.registered_nodes[nn].groups.lib_ecology_tree
is_removable = minetest.registered_nodes[nn].groups.lib_ecology_sapling
is_removable = minetest.registered_nodes[nn].groups.lib_ecology_leaves
is_removable = minetest.registered_nodes[nn].groups.lib_ecology_fruit
is_removable = minetest.registered_nodes[nn].groups.lib_ecology_plant
is_removable = minetest.registered_nodes[nn].groups.flora
is_removable = minetest.registered_nodes[nn].groups.flower
is_removable = minetest.registered_nodes[nn].groups.growing
if is_removable == nil or is_removable == 0 then
ground_y = y
break
end
end
end
if ground_y and ground_y >= 2 then
local p = {x=x,y=ground_y,z=z}
local ground_name = minetest.get_node(p)
local node_name = minetest.get_node(p).name
if ground_name == "lib_materials:liquid_water_source" then
return
end
-- if (not string.find(ground_name, "dirt")) or (not string.find(ground_name, "sand")) or (not string.find(ground_name, "snow")) or (not string.find(ground_name, "stone")) then
if (not string.find(ground_name, "sand")) or (not string.find(ground_name, "snow")) or (not string.find(ground_name, "stone")) then
return
end
local lx = pr:next(10,30)
local lz = pr:next(10,30)
if string.find(node_name, "_black") then
c_fluid_id = c_dirty
end
if string.find(node_name, "_brown") then
c_fluid_id = c_dirty
end
if string.find(node_name, "_rainforest") then
c_fluid_id = c_murky
end
if string.find(node_name, "_silt") then
c_fluid_id = c_murky
end
if string.find(node_name, "_mud") then
c_fluid_id = c_murky
end
if string.find(node_name, "_clay") then
c_fluid_id = c_muddy
end
if string.find(node_name, "_gravel") then
c_fluid_id = c_mud_dried
end
if string.find(node_name, "_sand") then
c_fluid_id = c_mud_dried
end
if string.find(node_name, "stone_") then
c_fluid_id = c_lava
end
if string.find(node_name, "snow") then
c_fluid_id = c_ice
end
if ground_y >= lib_materials.minheight_snow then
c_fluid_id = c_ice
end
if c_fluid_id then
else
c_fluid_id = c_river
end
-- if c_water == "" then
-- else
-- c_water = minetest.get_content_id("default:river_water_source")
-- end
lib_materials.lakes_fill(data, a, p, lx, lz)
--c_fluid_id = ""
end
end
end
end
-- Write to map
vm:set_data(data)
vm:update_liquids()
vm:write_to_map(data)
vm:update_map()
end
end)
--
-- Make lake
--
-- TODO: combine functions into one
local function check_x(data, a, x, y, z, lx, lz)
for xi = 0, lx do
local vi = a:index(x+xi, y, z)
if data[vi] == c_air or data[vi] == c_ignore then
return true
end
local vii = a:index(x+xi, y, z+lz)
if data[vii] == c_air or data[vii] == c_ignore then
return true
end
end
end
local function check_z(data, a, x, y, z, lx, lz)
for zi = 0, lz do
local vi = a:index(x, y, z+zi)
if data[vi] == c_air or data[vi] == c_ignore then
return true
end
local vii = a:index(x+lx, y, z+zi)
if data[vii] == c_air or data[vii] == c_ignore then
return true
end
end
end
local function leak(data, a, j, lx, lz)
for xi = 0, lx do
for zi = 0, lz do
local vi = a:index(xi, -j, zi)
if data[vi] == c_air or data[vi] == c_ignore then
return true
end
end
end
end
function lib_materials.lakes_fill(data, a, pos, lx, lz)
local x, y, z = pos.x, pos.y, pos.z
local water_a = VoxelArea:new{MinEdge={x=0, y=-32, z=0}, MaxEdge={x=lx, y=0, z=lz}}
local water_buffer = {}
-- Find upper start
local i = 0
while i <= 16 do
if check_x(data, a, x, y-i, z, lx, lz) or check_z(data, a, x, y-i, z, lx, lz) then
i = i + 1
else
break
end
end
if i >= 16 then return end
-- Itterate downwards
local j = i
while j <= (i+16) do
if check_x(data, a, x, y-j, z, lx, lz) or check_z(data, a, x, y-j, z, lx, lz) then
j = j - 1
break
else
j = j + 1
end
end
if j >= i+16 then return end
-- print ('[lib_lakes] i = '.. i ..'')
-- print ('[lib_lakes] j = '.. j ..'')
-- Check bottom
if leak(data, a, j, lx, lz) then return end
-- Add volume to buffer
for xi = 0, lx do
for yi = -i, -j, -1 do
for zi = 0, lz do
water_buffer[water_a:index(xi, yi, zi)] = true
end
end
end
-- Add the water
for xi = water_a.MinEdge.x, water_a.MaxEdge.x do
for yi = water_a.MinEdge.y, water_a.MaxEdge.y do
for zi = water_a.MinEdge.z, water_a.MaxEdge.z do
if a:contains(x+xi, y+yi, z+zi) then
local vi = a:index(x+xi, y+yi, z+zi)
if data[vi] == c_air or data[vi] == c_ignore then
if water_buffer[water_a:index(xi, yi, zi)] then
data[vi] = c_fluid_id
-- print ('[lib_lakes] Wasser auf (' .. x+xi .. ',' .. y+yi .. ',' .. z+zi .. ')')
end
end
end
end
end
end
end