mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-17 08:31:08 +01:00
200 lines
7.5 KiB
Lua
200 lines
7.5 KiB
Lua
local foundation_materials = {}
|
|
foundation_materials["mcl_core:sand"] = "mcl_core:sandstone"
|
|
foundation_materials["mcl_core:redsand"] = "mcl_core:redsandstone"
|
|
|
|
local function is_air(node)
|
|
return not node or node.name == "air" or node.name == "ignore" or node.name == "mcl_villages:no_paths"
|
|
end
|
|
local function is_solid(node)
|
|
if not node or node.name == "air" or node.name == "ignore" or node.name == "mcl_villages:no_paths" then return false end
|
|
--if string.find(node.name,"leaf") then return false end
|
|
--if string.find(node.name,"tree") then return false end
|
|
local ndef = minetest.registered_nodes[node.name]
|
|
return ndef and ndef.walkable
|
|
end
|
|
local function make_solid(lvm, cp, with, except)
|
|
local cur = lvm:get_node_at(cp)
|
|
if not is_solid(cur) or (except and cur.name == except.name) then
|
|
lvm:set_node_at(cp, with)
|
|
end
|
|
end
|
|
local function excavate(lvm,xi,yi,zi,pr)
|
|
local pos, n, c = vector.new(xi,yi,zi), nil, 0
|
|
local node = lvm:get_node_at(pos)
|
|
if is_air(node) then return false end -- already empty, nothing to do
|
|
pos.y = pos.y-1
|
|
if not is_air(lvm:get_node_at(pos)) then return false end -- below is solid, do not clear above anymore
|
|
-- count empty nodes below otherwise
|
|
for x = xi-1,xi+1 do
|
|
for z = zi-1,zi+1 do
|
|
pos.x, pos.z = x, z
|
|
if is_air(lvm:get_node_at(pos)) then c = c + 1 end
|
|
end
|
|
end
|
|
-- try to completely remove trees overhead
|
|
if not string.find(node.name, "leaf") and not string.find(node.name, "tree") then
|
|
-- stop randomly depending on fill, to narrow down the caves
|
|
if (pr:next(0,1e9)/1e9)^2 > c/9.1 then return false end
|
|
end
|
|
lvm:set_node_at(vector.new(xi, yi, zi),{name="air"})
|
|
return true -- modified
|
|
end
|
|
local function grow_foundation(lvm,xi,yi,zi,pr,surface_mat,platform_mat)
|
|
local pos, n, c = vector.new(xi,yi,zi), nil, 0
|
|
if is_solid(lvm:get_node_at(pos)) then return false end -- already solid, nothing to do
|
|
pos.y = pos.y+1
|
|
local cur = lvm:get_node_at(pos)
|
|
if not is_solid(cur) then return false end -- above is empty, do not fill below
|
|
if cur and cur.name and cur.name ~= surface_mat.name then platform_mat = cur end
|
|
if pr:next(1,5) == 5 then -- randomly switch to stone sometimes
|
|
platform_mat = { name = "mcl_core:stone" }
|
|
end
|
|
-- count solid nodes above otherwise
|
|
for x = xi-1,xi+1 do
|
|
for z = zi-1,zi+1 do
|
|
pos.x, pos.z = x, z
|
|
if is_solid(lvm:get_node_at(pos)) then c = c + 1 end
|
|
end
|
|
end
|
|
-- stop randomly depending on fill, to narrow down the foundation
|
|
if (pr:next(0,1e9)/1e9)^2 > c/9.1 then return false end
|
|
lvm:set_node_at(vector.new(xi, yi, zi), platform_mat)
|
|
return true -- modified
|
|
end
|
|
-------------------------------------------------------------------------------
|
|
-- function clear space above baseplate
|
|
-------------------------------------------------------------------------------
|
|
function mcl_villages.terraform(lvm, settlement, pr)
|
|
-- TODO: further optimize by using raw data arrays instead of set_node_at. But OK for a first draft.
|
|
--local lvm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
|
--local lvm = VoxelManip()
|
|
|
|
-- we make the foundations 1 node wider than requested, to have one node for path laying
|
|
for i, building in ipairs(settlement) do
|
|
--lvm:read_from_map(vector.new(pos.x-2, pos.y-20, pos.z-2), vector.new(pos.x+sx+2, pos.y+sy+20, pos.z+sz+2))
|
|
--lvm:get_data()
|
|
if not building.no_clearance then
|
|
local pos, size = building.pos, building.size
|
|
pos = vector.offset(pos, -math.floor(size.x/2)-1, 0, -math.floor(size.z/2)-1)
|
|
mcl_villages.clearance(lvm, pos.x, pos.y, pos.z, size.x+2, size.y, size.z+2, pr)
|
|
end
|
|
--lvm:write_to_map(false)
|
|
end
|
|
for i, building in ipairs(settlement) do
|
|
if not building.no_ground_turnip then
|
|
local pos, size = building.pos, building.size
|
|
local surface_mat = building.surface_mat
|
|
local platform_mat = building.platform_mat or { name = foundation_materials[surface_mat.name] or "mcl_core:dirt" }
|
|
building.platform_mat = platform_mat -- remember for use in schematic placement
|
|
pos = vector.offset(pos, -math.floor(size.x/2)-1, 0, -math.floor(size.z/2)-1)
|
|
mcl_villages.foundation(lvm, pos.x, pos.y, pos.z, size.x+2, -4, size.z+2, surface_mat, platform_mat, pr)
|
|
end
|
|
end
|
|
end
|
|
local AIR = {name = "air"}
|
|
function mcl_villages.clearance(lvm, px, py, pz, sx, sy, sz, pr)
|
|
-- excavate the needed volume, some headroom, and add a baseplate
|
|
for xi = px,px+sx-1 do
|
|
for zi = pz,pz+sz-1 do
|
|
lvm:set_node_at(vector.new(xi, py+1, zi),AIR)
|
|
-- py+2 to py+5 are filled larger below!
|
|
for yi = py+6,py+sy do
|
|
lvm:set_node_at(vector.new(xi, yi, zi),AIR)
|
|
end
|
|
end
|
|
end
|
|
-- slightly widen the cave, to make easier to enter for mobs
|
|
for xi = px-1,px+sx do
|
|
for zi = pz-1,pz+sz do
|
|
for yi = py+2,py+5 do
|
|
lvm:set_node_at(vector.new(xi, yi, zi),AIR)
|
|
end
|
|
end
|
|
end
|
|
-- some extra gaps
|
|
for xi = px-2,px+sx+1 do
|
|
for zi = pz-2,pz+sz+1 do
|
|
if pr:next(1,4) == 1 then
|
|
for yi = py+3,py+5 do
|
|
lvm:set_node_at(vector.new(xi, yi, zi),AIR)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- cave some additional area overhead, try to make it interesting though
|
|
for yi = py+3,py+sy*3 do
|
|
local active = false
|
|
for xi = px-2,px+sx+1 do
|
|
for zi = pz-2,pz+sz+1 do
|
|
if excavate(lvm,xi,yi,zi,pr) then active = true end
|
|
end
|
|
end
|
|
if not active and yi > py+sy+5 then break end
|
|
end
|
|
end
|
|
function mcl_villages.foundation(lvm, px, py, pz, sx, sy, sz, surface_mat, platform_mat, pr)
|
|
-- generate a baseplate
|
|
for xi = px,px+sx-1 do
|
|
for zi = pz,pz+sz-1 do
|
|
lvm:set_node_at(vector.new(xi, py, zi), surface_mat)
|
|
make_solid(lvm, vector.new(xi, py - 1, zi), platform_mat)
|
|
end
|
|
end
|
|
-- slightly widen the baseplate, to make easier to enter for mobs
|
|
for xi = px,px+sx-1 do
|
|
make_solid(lvm, vector.new(xi, py-1, pz-1), surface_mat, platform_mat)
|
|
make_solid(lvm, vector.new(xi, py-1, pz), platform_mat)
|
|
make_solid(lvm, vector.new(xi, py-1, pz+sz-1), platform_mat)
|
|
make_solid(lvm, vector.new(xi, py-1, pz+sz), surface_mat, platform_mat)
|
|
end
|
|
for zi = pz,pz+sz-1 do
|
|
make_solid(lvm, vector.new(px-1, py-1, zi), surface_mat, platform_mat)
|
|
make_solid(lvm, vector.new(px, py-1, zi), platform_mat)
|
|
make_solid(lvm, vector.new(px+sx-1, py-1, zi), platform_mat)
|
|
make_solid(lvm, vector.new(px+sx, py-1, zi), surface_mat, platform_mat)
|
|
end
|
|
-- make some additional steps, along both x sides
|
|
for xi = px,px+sx-1 do
|
|
local cp = vector.new(xi, py-3, pz-1)
|
|
if is_solid(lvm:get_node_at(cp)) then
|
|
cp = vector.new(xi, py-2, pz-1)
|
|
make_solid(lvm, cp, surface_mat, platform_mat)
|
|
cp.z = pz-2
|
|
make_solid(lvm, cp, surface_mat, platform_mat)
|
|
end
|
|
local cp = vector.new(xi, py-3, pz+sz)
|
|
if is_solid(lvm:get_node_at(cp)) then
|
|
cp = vector.new(xi, py-2, pz+sz)
|
|
make_solid(lvm, cp, surface_mat, platform_mat)
|
|
cp.z = pz + sz + 1
|
|
make_solid(lvm, cp, surface_mat, platform_mat)
|
|
end
|
|
end
|
|
-- make some additional steps, along both z sides
|
|
for zi = pz,pz+sz-1 do
|
|
local cp = vector.new(px-1, py-3, zi)
|
|
if is_solid(lvm:get_node_at(cp)) then
|
|
cp = vector.new(px-1, py-2, zi)
|
|
make_solid(lvm, cp, surface_mat, platform_mat)
|
|
cp.x = px-2
|
|
make_solid(lvm, cp, surface_mat, platform_mat)
|
|
end
|
|
local cp = vector.new(px+sx, py-3, zi)
|
|
if is_solid(lvm:get_node_at(cp)) then
|
|
cp = vector.new(px+sx, py-2, zi)
|
|
make_solid(lvm, cp, surface_mat, platform_mat)
|
|
cp.x = px+sx+1
|
|
make_solid(lvm, cp, surface_mat, platform_mat)
|
|
end
|
|
end
|
|
-- construct additional baseplate below, also try to make it interesting
|
|
for yi = py-2,py-20,-1 do
|
|
local active = false
|
|
for xi = px-1,px+sx do
|
|
for zi = pz-1,pz+sz do
|
|
if grow_foundation(lvm,xi,yi,zi,pr,surface_mat,platform_mat) then active = true end
|
|
end
|
|
end
|
|
if not active and yi < py + sy then break end
|
|
end
|
|
end
|