added simple ground raising for villages to prevent floating villages near cliffs

This commit is contained in:
kaadmy 2015-10-22 16:27:35 -07:00
parent 048616b0b3
commit 5e4f7fa639
3 changed files with 115 additions and 48 deletions

View File

@ -74,13 +74,15 @@ if minetest.setting_getbool("fixlight_command_enable") then
}) })
end end
function util.nodefunc(pos1, pos2, name, func) function util.nodefunc(pos1, pos2, name, func, nomanip)
-- function based off fixlight -- function based off fixlight
-- call a function for every node of a single type -- call a function for every node of a single type
local pos1, pos2 = util.sort_pos(pos1, pos2) local pos1, pos2 = util.sort_pos(pos1, pos2)
local manip = minetest.get_voxel_manip() if not nomanip then
manip:read_from_map(pos1, pos2) local manip = minetest.get_voxel_manip()
manip:read_from_map(pos1, pos2)
end
local nodes = minetest.find_nodes_in_area(pos1, pos2, name) local nodes = minetest.find_nodes_in_area(pos1, pos2, name)
for _, pos in ipairs(nodes) do for _, pos in ipairs(nodes) do
@ -99,13 +101,15 @@ function util.getvoxelmanip(pos1, pos2)
return manip return manip
end end
function util.remove_area(pos1, pos2) function util.remove_area(pos1, pos2, nomanip)
-- function based off fixlight -- function based off fixlight
-- call a function for every node of a single type -- call a function for every node of a single type
local pos1, pos2 = util.sort_pos(pos1, pos2) local pos1, pos2 = util.sort_pos(pos1, pos2)
local manip = minetest.get_voxel_manip() if not nomanip then
manip:read_from_map(pos1, pos2) local manip = minetest.get_voxel_manip()
manip:read_from_map(pos1, pos2)
end
for i = pos1.x, pos2.x-1 do for i = pos1.x, pos2.x-1 do
for j = pos1.y, pos2.y-1 do for j = pos1.y, pos2.y-1 do
@ -118,13 +122,15 @@ function util.remove_area(pos1, pos2)
manip:write_to_map() manip:write_to_map()
end end
function util.areafunc(pos1, pos2, func) function util.areafunc(pos1, pos2, func, nomanip)
-- function based off fixlight -- function based off fixlight
-- call a function for every node of a single type -- call a function for every node of a single type
local pos1, pos2 = util.sort_pos(pos1, pos2) local pos1, pos2 = util.sort_pos(pos1, pos2)
local manip = minetest.get_voxel_manip() if not nomanip then
manip:read_from_map(pos1, pos2) local manip = minetest.get_voxel_manip()
manip:read_from_map(pos1, pos2)
end
for i = pos1.x, pos2.x-1 do for i = pos1.x, pos2.x-1 do
for j = pos1.y, pos2.y-1 do for j = pos1.y, pos2.y-1 do
@ -135,13 +141,15 @@ function util.areafunc(pos1, pos2, func)
end end
end end
function util.reconstruct(pos1, pos2) function util.reconstruct(pos1, pos2, nomanip)
-- function based off fixlight -- function based off fixlight
-- force a re-construction of the nodes in an area, for fixing missing metadata in schematics -- force a re-construction of the nodes in an area, for fixing missing metadata in schematics
local pos1, pos2 = util.sort_pos(pos1, pos2) local pos1, pos2 = util.sort_pos(pos1, pos2)
local manip = minetest.get_voxel_manip() if not nomanip then
manip:read_from_map(pos1, pos2) local manip = minetest.get_voxel_manip()
manip:read_from_map(pos1, pos2)
end
-- fix chests -- fix chests
local nodes = minetest.find_nodes_in_area(pos1, pos2, "default:chest") local nodes = minetest.find_nodes_in_area(pos1, pos2, "default:chest")

View File

@ -142,39 +142,90 @@ village.chunktypes = {
"orchard", "orchard",
} }
function village.get_area_height(minp, maxp) function village.lift_ground(pos, scanheight)
local minp, maxp = util.sort_pos(minp, maxp) -- assume ground is lower than pos.y
local avg = 0 local topnode = nil
local amt = 0 local topdepth = 0
for y = minp.y, maxp.y-1 do local fillernode = nil
for x = minp.x, maxp.x-1 do local fillerdepth = 0
for z = minp.z, maxp.z-1 do
if minetest.get_node({x = x, y = y, z = z}).name == "air" or minetest.get_node({x = x, y = y, z = z}).name == "ignore" then local stonenode = nil
avg = avg + y
amt = amt + 1 for y = pos.y, pos.y - scanheight, -1 do
local p = {x = pos.x, y = y, z = pos.z}
local nn = minetest.get_node(p).name
local an = minetest.get_node({x = p.x, y = p.y + 1, z = p.z}).name
if nn ~= "air" then
local nd = minetest.registered_nodes[nn]
if not nd.buildable_to then -- avoid grass, fluids, etc.
if topnode == nil and nn ~= an then
topnode = nn
elseif fillernode == nil and nn ~= an then
fillernode = nn
else
stonenode = nn
end end
end end
if fillernode and not stonenode then
fillerdepth = fillerdepth + 1
elseif topnode and not fillernode then
topdepth = topdepth + 1
end
end end
end end
avg = avg / amt if topnode == nil then
topnode = "default:dirt_with_grass"
topdepth = 1
end
if fillernode == nil then
fillernode = "default:dirt"
fillerdepth = 3
end
if stonenode == nil then
stonenode = fillernode
end
return avg for y = pos.y - scanheight, pos.y do
local p = {x = pos.x, y = y, z = pos.z}
local th = pos.y - y
if th <= fillerdepth - topdepth then
minetest.set_node(p, {name = fillernode})
elseif th <= topdepth then
minetest.set_node(p, {name = topnode})
else
minetest.set_node(p, {name = stonenode})
end
end
end end
function village.spawn_chunk(pos, orient, replace, pr, chunktype, nofill) function village.spawn_chunk(pos, orient, replace, pr, chunktype, nofill)
util.getvoxelmanip(pos, {x = pos.x+12, y = pos.y+16, z = pos.z+12}) util.getvoxelmanip(pos, {x = pos.x+12, y = pos.y+12, z = pos.z+12})
if nofill ~= true then if nofill ~= true then
util.nodefunc(
{x = pos.x-6, y = pos.y-7, z = pos.z-6},
{x = pos.x+17, y = pos.y-6, z = pos.z+17},
"air",
function(pos)
village.lift_ground(pos, 15) -- distance to lift ground; larger numbers will be slower
end, true)
minetest.place_schematic( minetest.place_schematic(
{x = pos.x, y = pos.y, z = pos.z}, pos,
mp.."/schematics/village_empty.mts", mp.."/schematics/village_empty.mts",
"0", "0",
{}, {},
true true
) )
minetest.place_schematic( minetest.place_schematic(
{x = pos.x-6, y = pos.y-5, z = pos.z-6}, {x = pos.x-6, y = pos.y-5, z = pos.z-6},
mp.."/schematics/village_filler.mts", mp.."/schematics/village_filler.mts",
@ -192,24 +243,24 @@ function village.spawn_chunk(pos, orient, replace, pr, chunktype, nofill)
true true
) )
util.reconstruct(pos, {x = pos.x+12, y = pos.y+16, z = pos.z+12}) util.reconstruct(pos, {x = pos.x+12, y = pos.y+12, z = pos.z+12})
util.fixlight(pos, {x = pos.x+12, y = pos.y+16, z = pos.z+12}) util.fixlight(pos, {x = pos.x+12, y = pos.y+12, z = pos.z+12})
util.nodefunc( util.nodefunc(
pos, pos,
{x = pos.x+12, y = pos.y+16, z = pos.z+12}, {x = pos.x+12, y = pos.y+12, z = pos.z+12},
"default:chest", "default:chest",
function(pos) function(pos)
goodies.fill(pos, chunktype, pr, "main", 3) goodies.fill(pos, chunktype, pr, "main", 3)
end) end, true)
util.nodefunc( util.nodefunc(
pos, pos,
{x = pos.x+12, y = pos.y+16, z = pos.z+12}, {x = pos.x+12, y = pos.y+12, z = pos.z+12},
"music:player", "music:player",
function(pos) function(pos)
if pr:next(1, 2) > 1 then if pr:next(1, 2) > 1 then
minetest.remove_node(pos) minetest.remove_node(pos)
end end
end) end, true)
local chunkdef = village.chunkdefs[chunktype] local chunkdef = village.chunkdefs[chunktype]
if chunkdef ~= nil then if chunkdef ~= nil then
@ -217,7 +268,7 @@ function village.spawn_chunk(pos, orient, replace, pr, chunktype, nofill)
if chunkdef.entity_chance ~= nil and pr:next(1, chunkdef.entity_chance) == 1 then if chunkdef.entity_chance ~= nil and pr:next(1, chunkdef.entity_chance) == 1 then
util.nodefunc( util.nodefunc(
pos, pos,
{x = pos.x+12, y = pos.y+16, z = pos.z+12}, {x = pos.x+12, y = pos.y+12, z = pos.z+12},
"village:entity_spawner", "village:entity_spawner",
function(pos) function(pos)
minetest.remove_node(pos) minetest.remove_node(pos)
@ -229,12 +280,12 @@ function village.spawn_chunk(pos, orient, replace, pr, chunktype, nofill)
util.nodefunc( util.nodefunc(
pos, pos,
{x = pos.x+12, y = pos.y+16, z = pos.z+12}, {x = pos.x+12, y = pos.y+12, z = pos.z+12},
"village:entity_spawner", "village:entity_spawner",
function(pos) function(pos)
table.insert(ent_spawns, pos) table.insert(ent_spawns, pos)
minetest.remove_node(pos) minetest.remove_node(pos)
end) end, true)
if #ent_spawns > 0 then if #ent_spawns > 0 then
for ent, amt in pairs(chunkdef.entities) do for ent, amt in pairs(chunkdef.entities) do
@ -253,13 +304,13 @@ function village.spawn_chunk(pos, orient, replace, pr, chunktype, nofill)
if chunktype == "forge" then if chunktype == "forge" then
util.nodefunc( util.nodefunc(
pos, pos,
{x = pos.x+12, y = pos.y+16, z = pos.z+12}, {x = pos.x+12, y = pos.y+12, z = pos.z+12},
"default:furnace", "default:furnace",
function(pos) function(pos)
goodies.fill(pos, "FURNACE_SRC", pr, "src", 1) goodies.fill(pos, "FURNACE_SRC", pr, "src", 1)
goodies.fill(pos, "FURNACE_DST", pr, "dst", 1) goodies.fill(pos, "FURNACE_DST", pr, "dst", 1)
goodies.fill(pos, "FURNACE_FUEL", pr, "fuel", 1) goodies.fill(pos, "FURNACE_FUEL", pr, "fuel", 1)
end) end, true)
end end
end end
@ -282,15 +333,17 @@ function village.spawn_road(pos, houses, built, roads, depth, pr)
nextpos.x = nextpos.x + 12 nextpos.x = nextpos.x + 12
end end
if built[minetest.hash_node_position(nextpos)] == nil then local hnp = minetest.hash_node_position(nextpos)
built[minetest.hash_node_position(nextpos)] = true
if built[hnp] == nil then
built[hnp] = true
if depth <= 0 or pr:next(1, 8) < 6 then if depth <= 0 or pr:next(1, 8) < 6 then
houses[minetest.hash_node_position(nextpos)] = {pos = nextpos, front = pos} houses[hnp] = {pos = nextpos, front = pos}
local structure = util.choice_element(village.chunktypes, pr) local structure = util.choice_element(village.chunktypes, pr)
village.spawn_chunk(nextpos, orient, {}, pr, structure) village.spawn_chunk(nextpos, orient, {}, pr, structure)
else else
roads[minetest.hash_node_position(nextpos)] = {pos = nextpos} roads[hnp] = {pos = nextpos}
village.spawn_road(nextpos, houses, built, roads, depth - 1, pr) village.spawn_road(nextpos, houses, built, roads, depth - 1, pr)
end end
end end
@ -314,23 +367,29 @@ function village.spawn_village(pos, pr)
local built = {} local built = {}
local roads = {} local roads = {}
local spawnpos = pos
village.spawn_chunk(pos, "0", {}, pr, "well") village.spawn_chunk(pos, "0", {}, pr, "well")
built[minetest.hash_node_position(pos)] = true built[minetest.hash_node_position(pos)] = true
local t1 = os.clock()
village.spawn_road(pos, houses, built, roads, depth, pr) village.spawn_road(pos, houses, built, roads, depth, pr)
print(string.format("Took %.2fms to spawn village", (os.clock() - t1) * 1000))
local function connects(pos, nextpos) local function connects(pos, nextpos)
if houses[minetest.hash_node_position(nextpos)] ~= nil then local hnp = minetest.hash_node_position(nextpos)
if vector.equals(houses[minetest.hash_node_position(nextpos)].front, pos) then
if houses[hnp] ~= nil then
if vector.equals(houses[hnp].front, pos) then
return true return true
end end
end end
if roads[minetest.hash_node_position(nextpos)] ~= nil then if roads[hnp] ~= nil then
return true return true
end end
if vector.equals(pos, nextpos) then if vector.equals(pos, nextpos) or vector.equals(nextpos, spawnpos) then
return true return true
end end
end end