mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-19 09:31:07 +01:00
Add sub-map generators queue, fix https://git.minetest.land/MineClone2/MineClone2/issues/993 and https://git.minetest.land/MineClone2/MineClone2/issues/1060
This commit is contained in:
parent
d8b5620115
commit
89e55e9065
15 changed files with 944 additions and 801 deletions
|
@ -46,6 +46,42 @@ local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_
|
|||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
|
||||
|
||||
local function coordinate_to_block(x)
|
||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||
end
|
||||
|
||||
local function coordinate_to_chunk(x)
|
||||
return math.floor((coordinate_to_block(x) + central_chunk_offset) / mcl_vars.chunksize)
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / chunk_size_in_nodes)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_vars.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
if not superflat and not singlenode then
|
||||
-- Normal mode
|
||||
--[[ Realm stacking (h is for height)
|
||||
|
@ -91,7 +127,7 @@ else
|
|||
mcl_vars.mg_bedrock_is_rough = false
|
||||
end
|
||||
|
||||
mcl_vars.mg_overworld_max = 31000
|
||||
mcl_vars.mg_overworld_max = mcl_vars.mapgen_edge_max
|
||||
|
||||
-- The Nether (around Y = -29000)
|
||||
mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border
|
||||
|
|
|
@ -405,53 +405,3 @@ function mcl_util.get_object_center(obj)
|
|||
pos.y = pos.y + (ymax - ymin) / 2.0
|
||||
return pos
|
||||
end
|
||||
|
||||
local get_node_emerge_queue = {}
|
||||
local function ecb_get_far_node(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining <= 0 and param then
|
||||
minetest.log("verbose","[mcl_util] ecb done for param = "..param.." node.name="..minetest.get_node(minetest.string_to_pos(param)).name)
|
||||
get_node_emerge_queue[param] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.get_far_node(pos, force)
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" then
|
||||
return node
|
||||
end
|
||||
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" or not force then
|
||||
return node
|
||||
end
|
||||
|
||||
local blockpos = vector.multiply(vector.floor(vector.divide(pos, mcl_vars.MAP_BLOCKSIZE)), mcl_vars.MAP_BLOCKSIZE)
|
||||
local key = minetest.pos_to_string(blockpos)
|
||||
|
||||
for i=1,2 do -- give engine 2 chances to emerge the data
|
||||
if not get_node_emerge_queue[key] then
|
||||
get_node_emerge_queue[key] = 1
|
||||
minetest.log("verbose","[mcl_util] emerge during get_far_node("..minetest.pos_to_string(pos).."), key="..key..", blockpos="..minetest.pos_to_string(blockpos))
|
||||
minetest.emerge_area(blockpos, vector.add(blockpos, mcl_vars.MAP_BLOCKSIZE-1), ecb_get_far_node, key)
|
||||
end
|
||||
|
||||
while not get_node_emerge_queue[key] do end
|
||||
minetest.log("verbose","[mcl_util] emerge finished for node "..minetest.pos_to_string(pos)..", key="..key..", blockpos="..minetest.pos_to_string(blockpos)..", node.name="..mcl_util.get_far_node(pos).name)
|
||||
|
||||
node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" then
|
||||
return node
|
||||
end
|
||||
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" or not force then
|
||||
return node
|
||||
end
|
||||
end
|
||||
|
||||
node.name = "air" -- engine continuously returns "ignore" - probably it is a bug
|
||||
minetest.swap_node(pos, node) -- engine continuously returns "ignore" - probably it is a bug
|
||||
return node -- engine continuously returns "ignore" - probably it is a bug
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mcl_init
|
||||
mcl_mapgen_core
|
||||
mcl_core
|
||||
mcl_worlds
|
||||
mcl_farming
|
||||
|
|
|
@ -3967,7 +3967,7 @@ if mg_name ~= "singlenode" then
|
|||
-- Overworld decorations for v6 are handled in mcl_mapgen_core
|
||||
|
||||
if deco_id_chorus_plant then
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed)
|
||||
mcl_mapgen_core.register_generator("chorus_grow", nil, function(minp, maxp, blockseed)
|
||||
local gennotify = minetest.get_mapgen_object("gennotify")
|
||||
local poslist = {}
|
||||
for _, pos in ipairs(gennotify["decoration#"..deco_id_chorus_plant] or {}) do
|
||||
|
|
|
@ -1,17 +1,38 @@
|
|||
-- FIXME: Chests may appear at openings
|
||||
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local pr = PseudoRandom(os.time())
|
||||
|
||||
-- Are dungeons disabled?
|
||||
if mcl_vars.mg_dungeons == false then
|
||||
if mcl_vars.mg_dungeons == false or mg_name == "singlenode" then
|
||||
return
|
||||
end
|
||||
|
||||
if mg_name ~= "singlenode" then
|
||||
-- Get loot for dungeon chests
|
||||
local get_loot = function()
|
||||
local loottable = {
|
||||
local min_y = math.max(mcl_vars.mg_overworld_min, mcl_vars.mg_bedrock_overworld_max) + 1
|
||||
local max_y = mcl_vars.mg_overworld_max - 1
|
||||
|
||||
local dungeonsizes = {
|
||||
{ x=5, y=4, z=5},
|
||||
{ x=5, y=4, z=7},
|
||||
{ x=7, y=4, z=5},
|
||||
{ x=7, y=4, z=7},
|
||||
}
|
||||
|
||||
local dirs = {
|
||||
{ x= 1, y=0, z= 0 },
|
||||
{ x= 0, y=0, z= 1 },
|
||||
{ x=-1, y=0, z= 0 },
|
||||
{ x= 0, y=0, z=-1 },
|
||||
}
|
||||
|
||||
local surround_vectors = {
|
||||
{ x=-1, y=0, z=0 },
|
||||
{ x=1, y=0, z=0 },
|
||||
{ x=0, y=0, z=-1 },
|
||||
{ x=0, y=0, z=1 },
|
||||
}
|
||||
|
||||
local loottable =
|
||||
{
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 3,
|
||||
|
@ -54,347 +75,278 @@ local get_loot = function()
|
|||
{ itemstring = "mcl_mobitems:string", weight = 10, amount_min = 1, amount_max = 8 },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
-- Bonus loot for v6 mapgen: Otherwise unobtainable saplings.
|
||||
if mg_name == "v6" then
|
||||
table.insert(loottable, {
|
||||
stacks_min = 1,
|
||||
stacks_max = 3,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:birchsapling", weight = 1, amount_min = 1, amount_max = 2 },
|
||||
{ itemstring = "mcl_core:acaciasapling", weight = 1, amount_min = 1, amount_max = 2 },
|
||||
{ itemstring = "", weight = 6 },
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
-- Calculate the number of dungeon spawn attempts
|
||||
-- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks).
|
||||
-- Minetest chunks don't have this size, so scale the number accordingly.
|
||||
local attempts = math.ceil(((mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE) ^ 3) / 8192) -- 63 = 80*80*80/8192
|
||||
|
||||
local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
|
||||
local p1, p2, dim, pr = param.p1, param.p2, param.dim, param.pr
|
||||
local x, y, z = p1.x, p1.y, p1.z
|
||||
|
||||
-- Check floor and ceiling: Must be *completely* solid
|
||||
local y_floor = y
|
||||
local y_ceiling = y + dim.y + 1
|
||||
for tx = x, x + dim.x do for tz = z, z + dim.z do
|
||||
if not minetest.registered_nodes[mcl_mapgen_core.get_node({x = tx, y = y_floor , z = tz}).name].walkable
|
||||
or not minetest.registered_nodes[mcl_mapgen_core.get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end
|
||||
end end
|
||||
|
||||
-- Check for air openings (2 stacked air at ground level) in wall positions
|
||||
local openings_counter = 0
|
||||
-- Store positions of openings; walls will not be generated here
|
||||
local openings = {}
|
||||
-- Corners are stored because a corner-only opening needs to be increased,
|
||||
-- so entities can get through.
|
||||
local corners = {}
|
||||
|
||||
local walls = {
|
||||
-- walls along x axis (contain corners)
|
||||
{ x, x+dim.x+1, "x", "z", z },
|
||||
{ x, x+dim.x+1, "x", "z", z+dim.z+1 },
|
||||
-- walls along z axis (exclude corners)
|
||||
{ z+1, z+dim.z, "z", "x", x },
|
||||
{ z+1, z+dim.z, "z", "x", x+dim.x+1 },
|
||||
}
|
||||
|
||||
-- Bonus loot for v6 mapgen: Otherwise unobtainable saplings.
|
||||
if mg_name == "v6" then
|
||||
table.insert(loottable, {
|
||||
stacks_min = 1,
|
||||
stacks_max = 3,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:birchsapling", weight = 1, amount_min = 1, amount_max = 2 },
|
||||
{ itemstring = "mcl_core:acaciasapling", weight = 1, amount_min = 1, amount_max = 2 },
|
||||
{ itemstring = "", weight = 6 },
|
||||
},
|
||||
})
|
||||
end
|
||||
local items = mcl_loot.get_multi_loot(loottable, pr)
|
||||
for w=1, #walls do
|
||||
local wall = walls[w]
|
||||
for iter = wall[1], wall[2] do
|
||||
local pos = {}
|
||||
pos[wall[3]] = iter
|
||||
pos[wall[4]] = wall[5]
|
||||
pos.y = y+1
|
||||
|
||||
return items
|
||||
end
|
||||
if openings[pos.x] == nil then openings[pos.x] = {} end
|
||||
local doorname1 = mcl_mapgen_core.get_node(pos).name
|
||||
pos.y = y+2
|
||||
local doorname2 = mcl_mapgen_core.get_node(pos).name
|
||||
if doorname1 == "air" and doorname2 == "air" then
|
||||
openings_counter = openings_counter + 1
|
||||
openings[pos.x][pos.z] = true
|
||||
|
||||
|
||||
-- Buffer for LuaVoxelManip
|
||||
local lvm_buffer = {}
|
||||
|
||||
-- Below the bedrock, generate air/void
|
||||
minetest.register_on_generated(function(minp, maxp)
|
||||
if maxp.y < mcl_vars.mg_overworld_min or minp.y > mcl_vars.mg_overworld_max then
|
||||
return
|
||||
-- Record corners
|
||||
if wall[3] == "x" and (iter == wall[1] or iter == wall[2]) then
|
||||
table.insert(corners, {x=pos.x, z=pos.z})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data(lvm_buffer)
|
||||
local area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
|
||||
local lvm_used = false
|
||||
-- If all openings are only at corners, the dungeon can't be accessed yet.
|
||||
-- This code extends the openings of corners so they can be entered.
|
||||
if openings_counter >= 1 and openings_counter == #corners then
|
||||
for c=1, #corners do
|
||||
-- Prevent creating too many openings because this would lead to dungeon rejection
|
||||
if openings_counter >= 5 then
|
||||
break
|
||||
end
|
||||
-- A corner is widened by adding openings to both neighbors
|
||||
local cx, cz = corners[c].x, corners[c].z
|
||||
local cxn, czn = cx, cz
|
||||
if x == cx then
|
||||
cxn = cxn + 1
|
||||
else
|
||||
cxn = cxn - 1
|
||||
end
|
||||
if z == cz then
|
||||
czn = czn + 1
|
||||
else
|
||||
czn = czn - 1
|
||||
end
|
||||
openings[cx][czn] = true
|
||||
openings_counter = openings_counter + 1
|
||||
if openings_counter < 5 then
|
||||
openings[cxn][cz] = true
|
||||
openings_counter = openings_counter + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local c_cobble = minetest.get_content_id("mcl_core:cobble")
|
||||
local c_mossycobble = minetest.get_content_id("mcl_core:mossycobble")
|
||||
-- Check conditions. If okay, start generating
|
||||
if openings_counter < 1 or openings_counter > 5 then return end
|
||||
|
||||
minetest.log("action","[mcl_dungeons] Placing new dungeon at "..minetest.pos_to_string({x=x,y=y,z=z}))
|
||||
-- Okay! Spawning starts!
|
||||
|
||||
-- Remember spawner chest positions to set metadata later
|
||||
local chest_posses = {}
|
||||
local chests = {}
|
||||
local spawner_posses = {}
|
||||
|
||||
-- Calculate the number of dungeon spawn attempts
|
||||
local sizevector = vector.subtract(maxp, minp)
|
||||
sizevector = vector.add(sizevector, 1)
|
||||
local chunksize = sizevector.x * sizevector.y * sizevector.z
|
||||
-- First prepare random chest positions.
|
||||
-- Chests spawn at wall
|
||||
|
||||
-- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks).
|
||||
-- Minetest chunks don't have this size, so scale the number accordingly.
|
||||
local attempts = math.ceil(chunksize / 65536 * 8)
|
||||
|
||||
for a=1, attempts do
|
||||
local x, y, z
|
||||
local b = 7 -- buffer
|
||||
x = math.random(minp.x+b, maxp.x-b)
|
||||
|
||||
local ymin = math.min(mcl_vars.mg_overworld_max, math.max(minp.y, mcl_vars.mg_bedrock_overworld_max) + 7)
|
||||
local ymax = math.min(mcl_vars.mg_overworld_max, math.max(maxp.y, mcl_vars.mg_bedrock_overworld_max) - 4)
|
||||
|
||||
y = math.random(ymin, ymax)
|
||||
z = math.random(minp.z+b, maxp.z-b)
|
||||
|
||||
local dungeonsizes = {
|
||||
{ x=5, y=4, z=5},
|
||||
{ x=5, y=4, z=7},
|
||||
{ x=7, y=4, z=5},
|
||||
{ x=7, y=4, z=7},
|
||||
}
|
||||
local dim = dungeonsizes[math.random(1, #dungeonsizes)]
|
||||
|
||||
-- Check floor and ceiling: Must be *completely* solid
|
||||
local ceilingfloor_ok = true
|
||||
for tx = x, x+dim.x do
|
||||
for tz = z, z+dim.z do
|
||||
local floor = minetest.get_name_from_content_id(data[area:index(tx, y, tz)])
|
||||
local ceiling = minetest.get_name_from_content_id(data[area:index(tx, y+dim.y+1, tz)])
|
||||
if (not minetest.registered_nodes[floor].walkable) or (not minetest.registered_nodes[ceiling].walkable) then
|
||||
ceilingfloor_ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if not ceilingfloor_ok then break end
|
||||
-- We assign each position at the wall a number and each chest gets one of these numbers randomly
|
||||
local totalChests = 2 -- this code strongly relies on this number being 2
|
||||
local totalChestSlots = (dim.x-1) * (dim.z-1)
|
||||
local chestSlots = {}
|
||||
-- There is a small chance that both chests have the same slot.
|
||||
-- In that case, we give a 2nd chance for the 2nd chest to get spawned.
|
||||
-- If it failed again, tough luck! We stick with only 1 chest spawned.
|
||||
local lastRandom
|
||||
local secondChance = true -- second chance is still available
|
||||
for i=1, totalChests do
|
||||
local r = pr:next(1, totalChestSlots)
|
||||
if r == lastRandom and secondChance then
|
||||
-- Oops! Same slot selected. Try again.
|
||||
r = pr:next(1, totalChestSlots)
|
||||
secondChance = false
|
||||
end
|
||||
lastRandom = r
|
||||
table.insert(chestSlots, r)
|
||||
end
|
||||
table.sort(chestSlots)
|
||||
local currentChest = 1
|
||||
|
||||
-- Check for air openings (2 stacked air at ground level) in wall positions
|
||||
local openings_counter = 0
|
||||
-- Store positions of openings; walls will not be generated here
|
||||
local openings = {}
|
||||
-- Corners are stored because a corner-only opening needs to be increased,
|
||||
-- so entities can get through.
|
||||
local corners = {}
|
||||
if ceilingfloor_ok then
|
||||
|
||||
local walls = {
|
||||
-- walls along x axis (contain corners)
|
||||
{ x, x+dim.x+1, "x", "z", z },
|
||||
{ x, x+dim.x+1, "x", "z", z+dim.z+1 },
|
||||
-- walls along z axis (exclude corners)
|
||||
{ z+1, z+dim.z, "z", "x", x },
|
||||
{ z+1, z+dim.z, "z", "x", x+dim.x+1 },
|
||||
}
|
||||
|
||||
for w=1, #walls do
|
||||
local wall = walls[w]
|
||||
for iter = wall[1], wall[2] do
|
||||
local pos = {}
|
||||
pos[wall[3]] = iter
|
||||
pos[wall[4]] = wall[5]
|
||||
pos.y = y+1
|
||||
|
||||
if openings[pos.x] == nil then openings[pos.x] = {} end
|
||||
|
||||
local door1 = area:index(pos.x, pos.y, pos.z)
|
||||
pos.y = y+2
|
||||
local door2 = area:index(pos.x, pos.y, pos.z)
|
||||
local doorname1 = minetest.get_name_from_content_id(data[door1])
|
||||
local doorname2 = minetest.get_name_from_content_id(data[door2])
|
||||
if doorname1 == "air" and doorname2 == "air" then
|
||||
openings_counter = openings_counter + 1
|
||||
openings[pos.x][pos.z] = true
|
||||
|
||||
-- Record corners
|
||||
if wall[3] == "x" and (iter == wall[1] or iter == wall[2]) then
|
||||
table.insert(corners, {x=pos.x, z=pos.z})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If all openings are only at corners, the dungeon can't be accessed yet.
|
||||
-- This code extends the openings of corners so they can be entered.
|
||||
if openings_counter >= 1 and openings_counter == #corners then
|
||||
for c=1, #corners do
|
||||
-- Prevent creating too many openings because this would lead to dungeon rejection
|
||||
if openings_counter >= 5 then
|
||||
break
|
||||
end
|
||||
-- A corner is widened by adding openings to both neighbors
|
||||
local cx, cz = corners[c].x, corners[c].z
|
||||
local cxn, czn = cx, cz
|
||||
if x == cx then
|
||||
cxn = cxn + 1
|
||||
else
|
||||
cxn = cxn - 1
|
||||
end
|
||||
if z == cz then
|
||||
czn = czn + 1
|
||||
else
|
||||
czn = czn - 1
|
||||
end
|
||||
openings[cx][czn] = true
|
||||
openings_counter = openings_counter + 1
|
||||
if openings_counter < 5 then
|
||||
openings[cxn][cz] = true
|
||||
openings_counter = openings_counter + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check conditions. If okay, start generating
|
||||
if ceilingfloor_ok and openings_counter >= 1 and openings_counter <= 5 then
|
||||
-- Okay! Spawning starts!
|
||||
|
||||
-- First prepare random chest positions.
|
||||
-- Chests spawn at wall
|
||||
|
||||
-- We assign each position at the wall a number and each chest gets one of these numbers randomly
|
||||
local totalChests = 2 -- this code strongly relies on this number being 2
|
||||
local totalChestSlots = (dim.x-1) * (dim.z-1)
|
||||
local chestSlots = {}
|
||||
-- There is a small chance that both chests have the same slot.
|
||||
-- In that case, we give a 2nd chance for the 2nd chest to get spawned.
|
||||
-- If it failed again, tough luck! We stick with only 1 chest spawned.
|
||||
local lastRandom
|
||||
local secondChance = true -- second chance is still available
|
||||
for i=1, totalChests do
|
||||
local r = math.random(1, totalChestSlots)
|
||||
if r == lastRandom and secondChance then
|
||||
-- Oops! Same slot selected. Try again.
|
||||
r = math.random(1, totalChestSlots)
|
||||
secondChance = false
|
||||
end
|
||||
lastRandom = r
|
||||
table.insert(chestSlots, r)
|
||||
end
|
||||
table.sort(chestSlots)
|
||||
local currentChest = 1
|
||||
|
||||
-- Calculate the mob spawner position, to be re-used for later
|
||||
local spawner_pos = {x = x + math.ceil(dim.x/2), y = y+1, z = z + math.ceil(dim.z/2)}
|
||||
table.insert(spawner_posses, spawner_pos)
|
||||
|
||||
-- Generate walls and floor
|
||||
local maxx, maxy, maxz = x+dim.x+1, y+dim.y, z+dim.z+1
|
||||
local chestSlotCounter = 1
|
||||
for tx = x, maxx do
|
||||
for tz = z, maxz do
|
||||
for ty = y, maxy do
|
||||
local p_pos = area:index(tx, ty, tz)
|
||||
|
||||
-- Do not overwrite nodes with is_ground_content == false (e.g. bedrock)
|
||||
-- Exceptions: cobblestone and mossy cobblestone so neighborings dungeons nicely connect to each other
|
||||
local name = minetest.get_name_from_content_id(data[p_pos])
|
||||
if name == "mcl_core:cobble" or name == "mcl_core:mossycobble" or minetest.registered_nodes[name].is_ground_content then
|
||||
-- Floor
|
||||
if ty == y then
|
||||
if math.random(1,4) == 1 then
|
||||
data[p_pos] = c_cobble
|
||||
else
|
||||
data[p_pos] = c_mossycobble
|
||||
end
|
||||
|
||||
-- Generate walls
|
||||
--[[ Note: No additional cobblestone ceiling is generated. This is intentional.
|
||||
The solid blocks above the dungeon are considered as the “ceiling”.
|
||||
It is possible (but rare) for a dungeon to generate below sand or gravel. ]]
|
||||
|
||||
elseif ty > y and (tx == x or tx == maxx or (tz == z or tz == maxz)) then
|
||||
-- Check if it's an opening first
|
||||
if (not openings[tx][tz]) or ty == maxy then
|
||||
-- Place wall or ceiling
|
||||
data[p_pos] = c_cobble
|
||||
elseif ty < maxy - 1 then
|
||||
-- Normally the openings are already clear, but not if it is a corner
|
||||
-- widening. Make sure to clear at least the bottom 2 nodes of an opening.
|
||||
data[p_pos] = c_air
|
||||
elseif ty == maxy - 1 and data[p_pos] ~= c_air then
|
||||
-- This allows for variation between 2-node and 3-node high openings.
|
||||
data[p_pos] = c_cobble
|
||||
end
|
||||
-- If it was an opening, the lower 3 blocks are not touched at all
|
||||
|
||||
-- Room interiour
|
||||
else
|
||||
local forChest = ty==y+1 and (tx==x+1 or tx==maxx-1 or tz==z+1 or tz==maxz-1)
|
||||
|
||||
-- Place next chest at the wall (if it was its chosen wall slot)
|
||||
if forChest and (currentChest < totalChests + 1) and (chestSlots[currentChest] == chestSlotCounter) then
|
||||
table.insert(chest_posses, {x=tx, y=ty, z=tz})
|
||||
currentChest = currentChest + 1
|
||||
else
|
||||
data[p_pos] = c_air
|
||||
end
|
||||
if forChest then
|
||||
chestSlotCounter = chestSlotCounter + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lvm_used = true
|
||||
-- Calculate the mob spawner position, to be re-used for later
|
||||
local sp = {x = x + math.ceil(dim.x/2), y = y+1, z = z + math.ceil(dim.z/2)}
|
||||
local rn = minetest.registered_nodes[mcl_mapgen_core.get_node(sp).name]
|
||||
if rn and rn.is_ground_content then
|
||||
table.insert(spawner_posses, sp)
|
||||
end
|
||||
|
||||
if lvm_used then
|
||||
local chest_param2 = {}
|
||||
-- Determine correct chest rotation (must pointi outwards)
|
||||
for c=1, #chest_posses do
|
||||
local cpos = chest_posses[c]
|
||||
-- Generate walls and floor
|
||||
local maxx, maxy, maxz = x+dim.x+1, y+dim.y, z+dim.z+1
|
||||
local chestSlotCounter = 1
|
||||
for tx = x, maxx do
|
||||
for tz = z, maxz do
|
||||
for ty = y, maxy do
|
||||
local p = {x = tx, y=ty, z=tz}
|
||||
|
||||
-- Check surroundings of chest to determine correct rotation
|
||||
local surround_vectors = {
|
||||
{ x=-1, y=0, z=0 },
|
||||
{ x=1, y=0, z=0 },
|
||||
{ x=0, y=0, z=-1 },
|
||||
{ x=0, y=0, z=1 },
|
||||
}
|
||||
local surroundings = {}
|
||||
|
||||
for s=1, #surround_vectors do
|
||||
-- Detect the 4 horizontal neighbors
|
||||
local spos = vector.add(cpos, surround_vectors[s])
|
||||
local wpos = vector.subtract(cpos, surround_vectors[s])
|
||||
local p_pos = area:index(spos.x, spos.y, spos.z)
|
||||
local p_pos2 = area:index(wpos.x, wpos.y, wpos.z)
|
||||
|
||||
local nodename = minetest.get_name_from_content_id(data[p_pos])
|
||||
local nodename2 = minetest.get_name_from_content_id(data[p_pos2])
|
||||
local nodedef = minetest.registered_nodes[nodename]
|
||||
local nodedef2 = minetest.registered_nodes[nodename2]
|
||||
-- The chest needs an open space in front of it and a walkable node (except chest) behind it
|
||||
if nodedef and nodedef.walkable == false and nodedef2 and nodedef2.walkable == true and nodename2 ~= "mcl_chests:chest" then
|
||||
table.insert(surroundings, spos)
|
||||
-- Do not overwrite nodes with is_ground_content == false (e.g. bedrock)
|
||||
-- Exceptions: cobblestone and mossy cobblestone so neighborings dungeons nicely connect to each other
|
||||
local name = mcl_mapgen_core.get_node(p).name
|
||||
if name == "mcl_core:cobble" or name == "mcl_core:mossycobble" or minetest.registered_nodes[name].is_ground_content then
|
||||
-- Floor
|
||||
if ty == y then
|
||||
if pr:next(1,4) == 1 then
|
||||
minetest.swap_node(p, {name = "mcl_core:cobble"})
|
||||
else
|
||||
minetest.swap_node(p, {name = "mcl_core:mossycobble"})
|
||||
end
|
||||
end
|
||||
-- Set param2 (=facedir) of this chest
|
||||
local facedir
|
||||
if #surroundings <= 0 then
|
||||
-- Fallback if chest ended up in the middle of a room for some reason
|
||||
facedir = math.random(0, 0)
|
||||
|
||||
-- Generate walls
|
||||
--[[ Note: No additional cobblestone ceiling is generated. This is intentional.
|
||||
The solid blocks above the dungeon are considered as the “ceiling”.
|
||||
It is possible (but rare) for a dungeon to generate below sand or gravel. ]]
|
||||
|
||||
elseif ty > y and (tx == x or tx == maxx or (tz == z or tz == maxz)) then
|
||||
-- Check if it's an opening first
|
||||
if (not openings[tx][tz]) or ty == maxy then
|
||||
-- Place wall or ceiling
|
||||
minetest.swap_node(p, {name = "mcl_core:cobble"})
|
||||
elseif ty < maxy - 1 then
|
||||
-- Normally the openings are already clear, but not if it is a corner
|
||||
-- widening. Make sure to clear at least the bottom 2 nodes of an opening.
|
||||
minetest.swap_node(p, {name = "air"})
|
||||
elseif ty == maxy - 1 and mcl_mapgen_core.get_node(p).name ~= "air" then
|
||||
-- This allows for variation between 2-node and 3-node high openings.
|
||||
minetest.swap_node(p, {name = "mcl_core:cobble"})
|
||||
end
|
||||
-- If it was an opening, the lower 3 blocks are not touched at all
|
||||
|
||||
-- Room interiour
|
||||
else
|
||||
-- 1 or multiple possible open directions: Choose random facedir
|
||||
local face_to = surroundings[math.random(1, #surroundings)]
|
||||
facedir = minetest.dir_to_facedir(vector.subtract(cpos, face_to))
|
||||
end
|
||||
chest_param2[c] = facedir
|
||||
end
|
||||
local forChest = ty==y+1 and (tx==x+1 or tx==maxx-1 or tz==z+1 or tz==maxz-1)
|
||||
|
||||
-- Finally generate the dungeons all at once (except the chests and the spawners)
|
||||
vm:set_data(data)
|
||||
vm:calc_lighting()
|
||||
vm:update_liquids()
|
||||
vm:write_to_map()
|
||||
|
||||
-- Chests are placed seperately
|
||||
for c=1, #chest_posses do
|
||||
local cpos = chest_posses[c]
|
||||
minetest.set_node(cpos, {name="mcl_chests:chest", param2=chest_param2[c]})
|
||||
local meta = minetest.get_meta(cpos)
|
||||
local inv = meta:get_inventory()
|
||||
local items = get_loot()
|
||||
mcl_loot.fill_inventory(inv, "main", items)
|
||||
end
|
||||
|
||||
-- Mob spawners are placed seperately, too
|
||||
-- We don't want to destroy non-ground nodes
|
||||
for s=1, #spawner_posses do
|
||||
local sp = spawner_posses[s]
|
||||
local n = minetest.get_name_from_content_id(data[area:index(sp.x,sp.y,sp.z)])
|
||||
if minetest.registered_nodes[n].is_ground_content then
|
||||
|
||||
-- ... and place it and select a random mob
|
||||
minetest.set_node(sp, {name = "mcl_mobspawners:spawner"})
|
||||
local mobs = {
|
||||
"mobs_mc:zombie",
|
||||
"mobs_mc:zombie",
|
||||
"mobs_mc:spider",
|
||||
"mobs_mc:skeleton",
|
||||
}
|
||||
local spawner_mob = mobs[math.random(1, #mobs)]
|
||||
|
||||
mcl_mobspawners.setup_spawner(sp, spawner_mob, 0, 7)
|
||||
-- Place next chest at the wall (if it was its chosen wall slot)
|
||||
if forChest and (currentChest < totalChests + 1) and (chestSlots[currentChest] == chestSlotCounter) then
|
||||
currentChest = currentChest + 1
|
||||
table.insert(chests, {x=tx, y=ty, z=tz})
|
||||
else
|
||||
minetest.swap_node(p, {name = "air"})
|
||||
end
|
||||
if forChest then
|
||||
chestSlotCounter = chestSlotCounter + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end end end
|
||||
|
||||
for c=#chests, 1, -1 do
|
||||
local pos = chests[c]
|
||||
|
||||
local surroundings = {}
|
||||
for s=1, #surround_vectors do
|
||||
-- Detect the 4 horizontal neighbors
|
||||
local spos = vector.add(pos, surround_vectors[s])
|
||||
local wpos = vector.subtract(pos, surround_vectors[s])
|
||||
local nodename = minetest.get_node(spos).name
|
||||
local nodename2 = minetest.get_node(wpos).name
|
||||
local nodedef = minetest.registered_nodes[nodename]
|
||||
local nodedef2 = minetest.registered_nodes[nodename2]
|
||||
-- The chest needs an open space in front of it and a walkable node (except chest) behind it
|
||||
if nodedef and nodedef.walkable == false and nodedef2 and nodedef2.walkable == true and nodename2 ~= "mcl_chests:chest" then
|
||||
table.insert(surroundings, spos)
|
||||
end
|
||||
end
|
||||
-- Set param2 (=facedir) of this chest
|
||||
local facedir
|
||||
if #surroundings <= 0 then
|
||||
-- Fallback if chest ended up in the middle of a room for some reason
|
||||
facedir = pr:next(0, 0)
|
||||
else
|
||||
-- 1 or multiple possible open directions: Choose random facedir
|
||||
local face_to = surroundings[pr:next(1, #surroundings)]
|
||||
facedir = minetest.dir_to_facedir(vector.subtract(pos, face_to))
|
||||
end
|
||||
|
||||
minetest.set_node(pos, {name="mcl_chests:chest", param2=facedir})
|
||||
local meta = minetest.get_meta(pos)
|
||||
mcl_loot.fill_inventory(meta:get_inventory(), "main", mcl_loot.get_multi_loot(loottable, pr))
|
||||
end
|
||||
|
||||
end)
|
||||
-- Mob spawners are placed seperately, too
|
||||
-- We don't want to destroy non-ground nodes
|
||||
for s=#spawner_posses, 1, -1 do
|
||||
local sp = spawner_posses[s]
|
||||
-- ... and place it and select a random mob
|
||||
minetest.set_node(sp, {name = "mcl_mobspawners:spawner"})
|
||||
local mobs = {
|
||||
"mobs_mc:zombie",
|
||||
"mobs_mc:zombie",
|
||||
"mobs_mc:spider",
|
||||
"mobs_mc:skeleton",
|
||||
}
|
||||
local spawner_mob = mobs[pr:next(1, #mobs)]
|
||||
|
||||
mcl_mobspawners.setup_spawner(sp, spawner_mob, 0, 7)
|
||||
end
|
||||
end
|
||||
|
||||
local function dungeons_nodes(minp, maxp, blockseed)
|
||||
local ymin, ymax = math.max(min_y, minp.y), math.min(max_y, maxp.y)
|
||||
if ymax < ymin then return false end
|
||||
local pr = PseudoRandom(blockseed)
|
||||
for a=1, attempts do
|
||||
local dim = dungeonsizes[pr:next(1, #dungeonsizes)]
|
||||
local x = pr:next(minp.x, maxp.x-dim.x-2)
|
||||
local y = pr:next(ymin , ymax -dim.y-2)
|
||||
local z = pr:next(minp.z, maxp.z-dim.z-2)
|
||||
local p1 = {x=x,y=y,z=z}
|
||||
local p2 = {x = x+dim.x+1, y = y+dim.y+1, z = z+dim.z+1}
|
||||
minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
local param = {p1=p1, p2=p2, dim=dim, pr=pr}
|
||||
minetest.emerge_area(p1, p2, ecb_spawn_dungeon, param)
|
||||
end
|
||||
end
|
||||
|
||||
mcl_mapgen_core.register_generator("dungeons", nil, dungeons_nodes, 999999)
|
||||
|
|
|
@ -1,3 +1,46 @@
|
|||
mcl_mapgen_core = {}
|
||||
mcl_mapgen_core.registered_generators = {}
|
||||
|
||||
local lvm, nodes, param2 = 0, 0, 0
|
||||
|
||||
local generating = {} -- generating chunks
|
||||
local chunks = {} -- intervals of chunks generated
|
||||
local function add_chunk(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local prev
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then -- we've found it
|
||||
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
||||
if n == d[1]-1 then -- right before:
|
||||
if prev and (prev[2] == n-1) then
|
||||
prev[2] = d[2]
|
||||
table.remove(chunks, i)
|
||||
return
|
||||
end
|
||||
d[1] = n
|
||||
return
|
||||
end
|
||||
if prev and (prev[2] == n-1) then --join to previous
|
||||
prev[2] = n
|
||||
return
|
||||
end
|
||||
table.insert(chunks, i, {n, n}) -- insert new interval before i
|
||||
return
|
||||
end
|
||||
prev = d
|
||||
end
|
||||
chunks[#chunks] = {n, n}
|
||||
end
|
||||
function mcl_mapgen_core.is_generated(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then
|
||||
return (n >= d[1])
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--
|
||||
-- Aliases for map generator outputs
|
||||
--
|
||||
|
@ -1190,12 +1233,14 @@ local perlin_structures
|
|||
local perlin_vines, perlin_vines_fine, perlin_vines_upwards, perlin_vines_length, perlin_vines_density
|
||||
local perlin_clay
|
||||
|
||||
local function generate_clay(minp, maxp, seed, voxelmanip_data, voxelmanip_area, lvm_used)
|
||||
local function generate_clay(minp, maxp, blockseed, voxelmanip_data, voxelmanip_area, lvm_used)
|
||||
-- TODO: Make clay generation reproducible for same seed.
|
||||
if maxp.y < -5 or minp.y > 0 then
|
||||
return lvm_used
|
||||
end
|
||||
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
perlin_clay = perlin_clay or minetest.get_perlin({
|
||||
offset = 0.5,
|
||||
scale = 0.2,
|
||||
|
@ -1212,18 +1257,18 @@ local function generate_clay(minp, maxp, seed, voxelmanip_data, voxelmanip_area,
|
|||
for divx=0+1,divs-2 do
|
||||
for divz=0+1,divs-2 do
|
||||
-- Get position and shift it a bit randomly so the clay do not obviously appear in a grid
|
||||
local cx = minp.x + math.floor((divx+0.5)*divlen) + math.random(-1,1)
|
||||
local cz = minp.z + math.floor((divz+0.5)*divlen) + math.random(-1,1)
|
||||
local cx = minp.x + math.floor((divx+0.5)*divlen) + pr:next(-1,1)
|
||||
local cz = minp.z + math.floor((divz+0.5)*divlen) + pr:next(-1,1)
|
||||
|
||||
local water_pos = voxelmanip_area:index(cx, y+1, cz)
|
||||
local waternode = voxelmanip_data[water_pos]
|
||||
local surface_pos = voxelmanip_area:index(cx, y, cz)
|
||||
local surfacenode = voxelmanip_data[surface_pos]
|
||||
|
||||
local genrnd = math.random(1, 20)
|
||||
local genrnd = pr:next(1, 20)
|
||||
if genrnd == 1 and perlin_clay:get_3d({x=cx,y=y,z=cz}) > 0 and waternode == c_water and
|
||||
(surfacenode == c_dirt or minetest.get_item_group(minetest.get_name_from_content_id(surfacenode), "sand") == 1) then
|
||||
local diamondsize = math.random(1, 3)
|
||||
local diamondsize = pr:next(1, 3)
|
||||
for x1 = -diamondsize, diamondsize do
|
||||
for z1 = -(diamondsize - math.abs(x1)), diamondsize - math.abs(x1) do
|
||||
local ccpos = voxelmanip_area:index(cx+x1, y, cz+z1)
|
||||
|
@ -1242,37 +1287,34 @@ local function generate_clay(minp, maxp, seed, voxelmanip_data, voxelmanip_area,
|
|||
end
|
||||
|
||||
-- TODO: Try to use more efficient structure generating code
|
||||
local function generate_structures(minp, maxp, seed, biomemap)
|
||||
local function generate_structures(minp, maxp, blockseed, biomemap)
|
||||
local chunk_has_desert_well = false
|
||||
local chunk_has_desert_temple = false
|
||||
local chunk_has_igloo = false
|
||||
local struct_min, struct_max = -3, 64
|
||||
local struct_min, struct_max = -3, 111 --64
|
||||
|
||||
if maxp.y >= struct_min and minp.y <= struct_max then
|
||||
-- Generate structures
|
||||
|
||||
local pr = PcgRandom(blockseed)
|
||||
perlin_structures = perlin_structures or minetest.get_perlin(329, 3, 0.6, 100)
|
||||
-- Assume X and Z lengths are equal
|
||||
local divlen = 5
|
||||
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)
|
||||
for x0 = minp.x, maxp.x, divlen do for z0 = minp.z, maxp.z, divlen do
|
||||
-- Determine amount from perlin noise
|
||||
local amount = math.floor(perlin_structures:get_2d({x=x0, y=z0}) * 9)
|
||||
-- Find random positions based on this random
|
||||
local pr = PseudoRandom(seed+1)
|
||||
local p, ground_y
|
||||
for i=0, amount do
|
||||
local x = pr:next(x0, x1)
|
||||
local z = pr:next(z0, z1)
|
||||
p = {x = pr:next(x0, x0+divlen-1), y = 0, z = pr:next(z0, z0+divlen-1)}
|
||||
-- Find ground level
|
||||
local ground_y = nil
|
||||
ground_y = nil
|
||||
local nn
|
||||
for y = struct_max, struct_min, -1 do
|
||||
local checknode = minetest.get_node_or_nil({x=x,y=y,z=z})
|
||||
p.y = y
|
||||
local checknode = minetest.get_node(p)
|
||||
if checknode then
|
||||
local def = minetest.registered_nodes[checknode.name]
|
||||
nn = checknode.name
|
||||
local def = minetest.registered_nodes[nn]
|
||||
if def and def.walkable then
|
||||
ground_y = y
|
||||
break
|
||||
|
@ -1281,21 +1323,17 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
end
|
||||
|
||||
if ground_y then
|
||||
local p = {x=x,y=ground_y+1,z=z}
|
||||
local nn = minetest.get_node(p).name
|
||||
p.y = ground_y+1
|
||||
local nn0 = minetest.get_node(p).name
|
||||
-- Check if the node can be replaced
|
||||
if minetest.registered_nodes[nn] and
|
||||
minetest.registered_nodes[nn].buildable_to then
|
||||
nn = minetest.get_node({x=x,y=ground_y,z=z}).name
|
||||
local struct = false
|
||||
|
||||
if minetest.registered_nodes[nn0] and minetest.registered_nodes[nn0].buildable_to then
|
||||
-- Desert temples and desert wells
|
||||
if nn == "mcl_core:sand" or (nn == "mcl_core:sandstone") then
|
||||
if not chunk_has_desert_temple and not chunk_has_desert_well and ground_y > 3 then
|
||||
-- Spawn desert temple
|
||||
-- TODO: Check surface
|
||||
if math.random(1,12000) == 1 then
|
||||
mcl_structures.call_struct(p, "desert_temple")
|
||||
if pr:next(1,12000) == 1 then
|
||||
mcl_structures.call_struct(p, "desert_temple", nil, pr)
|
||||
chunk_has_desert_temple = true
|
||||
end
|
||||
end
|
||||
|
@ -1303,11 +1341,11 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
local desert_well_prob = minecraft_chunk_probability(1000, minp, maxp)
|
||||
|
||||
-- Spawn desert well
|
||||
if math.random(1, desert_well_prob) == 1 then
|
||||
if pr:next(1, desert_well_prob) == 1 then
|
||||
-- Check surface
|
||||
local surface = minetest.find_nodes_in_area({x=p.x,y=p.y-1,z=p.z}, {x=p.x+5, y=p.y-1, z=p.z+5}, "mcl_core:sand")
|
||||
if #surface >= 25 then
|
||||
mcl_structures.call_struct(p, "desert_well")
|
||||
mcl_structures.call_struct(p, "desert_well", nil, pr)
|
||||
chunk_has_desert_well = true
|
||||
end
|
||||
end
|
||||
|
@ -1315,13 +1353,13 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
|
||||
-- Igloos
|
||||
elseif not chunk_has_igloo and (nn == "mcl_core:snowblock" or nn == "mcl_core:snow" or (minetest.get_item_group(nn, "grass_block_snow") == 1)) then
|
||||
if math.random(1, 4400) == 1 then
|
||||
if pr:next(1, 4400) == 1 then
|
||||
-- Check surface
|
||||
local floor = {x=p.x+9, y=p.y-1, z=p.z+9}
|
||||
local surface = minetest.find_nodes_in_area({x=p.x,y=p.y-1,z=p.z}, floor, "mcl_core:snowblock")
|
||||
local surface2 = minetest.find_nodes_in_area({x=p.x,y=p.y-1,z=p.z}, floor, "mcl_core:dirt_with_grass_snow")
|
||||
if #surface + #surface2 >= 63 then
|
||||
mcl_structures.call_struct(p, "igloo")
|
||||
mcl_structures.call_struct(p, "igloo", nil, pr)
|
||||
chunk_has_igloo = true
|
||||
end
|
||||
end
|
||||
|
@ -1331,16 +1369,16 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
if nn == "mcl_core:sandstone" or nn == "mcl_core:sand" and not chunk_has_desert_temple and ground_y > 3 then
|
||||
local fossil_prob = minecraft_chunk_probability(64, minp, maxp)
|
||||
|
||||
if math.random(1, fossil_prob) == 1 then
|
||||
if pr:next(1, fossil_prob) == 1 then
|
||||
-- Spawn fossil below desert surface between layers 40 and 49
|
||||
local p1 = {x=p.x, y=math.random(mcl_worlds.layer_to_y(40), mcl_worlds.layer_to_y(49)), z=p.z}
|
||||
local p1 = {x=p.x, y=pr:next(mcl_worlds.layer_to_y(40), mcl_worlds.layer_to_y(49)), z=p.z}
|
||||
-- Very rough check of the environment (we expect to have enough stonelike nodes).
|
||||
-- Fossils may still appear partially exposed in caves, but this is O.K.
|
||||
local p2 = vector.add(p1, 4)
|
||||
local nodes = minetest.find_nodes_in_area(p1, p2, {"mcl_core:sandstone", "mcl_core:stone", "mcl_core:diorite", "mcl_core:andesite", "mcl_core:granite", "mcl_core:stone_with_coal", "mcl_core:dirt", "mcl_core:gravel"})
|
||||
|
||||
if #nodes >= 100 then -- >= 80%
|
||||
mcl_structures.call_struct(p1, "fossil")
|
||||
mcl_structures.call_struct(p1, "fossil", nil, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1348,7 +1386,7 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
-- Witch hut
|
||||
if ground_y <= 0 and nn == "mcl_core:dirt" then
|
||||
local prob = minecraft_chunk_probability(48, minp, maxp)
|
||||
if math.random(1, prob) == 1 then
|
||||
if pr:next(1, prob) == 1 then
|
||||
|
||||
local swampland = minetest.get_biome_id("Swampland")
|
||||
local swampland_shore = minetest.get_biome_id("Swampland_shore")
|
||||
|
@ -1370,7 +1408,7 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
end
|
||||
|
||||
if here_be_witches then
|
||||
local r = tostring(math.random(0, 3) * 90) -- "0", "90", "180" or 270"
|
||||
local r = tostring(pr:next(0, 3) * 90) -- "0", "90", "180" or 270"
|
||||
local p1 = {x=p.x-1, y=WITCH_HUT_HEIGHT+2, z=p.z-1}
|
||||
local size
|
||||
if r == "0" or r == "180" then
|
||||
|
@ -1389,7 +1427,7 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
-- FIXME: For some mysterious reason (black magic?) this
|
||||
-- function does sometimes NOT spawn the witch hut. One can only see the
|
||||
-- oak wood nodes in the water, but no hut. :-/
|
||||
mcl_structures.call_struct(place, "witch_hut", r)
|
||||
mcl_structures.call_struct(place, "witch_hut", r, pr)
|
||||
|
||||
-- TODO: Spawn witch in or around hut when the mob sucks less.
|
||||
|
||||
|
@ -1451,7 +1489,7 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
-- Ice spikes in v6
|
||||
-- In other mapgens, ice spikes are generated as decorations.
|
||||
if mg_name == "v6" and not chunk_has_igloo and nn == "mcl_core:snowblock" then
|
||||
local spike = math.random(1, 58000)
|
||||
local spike = pr:next(1,58000)
|
||||
if spike < 3 then
|
||||
-- Check surface
|
||||
local floor = {x=p.x+4, y=p.y-1, z=p.z+4}
|
||||
|
@ -1460,7 +1498,7 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
local spruce_collisions = minetest.find_nodes_in_area({x=p.x+1,y=p.y+2,z=p.z+1}, {x=p.x+4, y=p.y+6, z=p.z+4}, {"mcl_core:sprucetree", "mcl_core:spruceleaves"})
|
||||
|
||||
if #surface >= 9 and #spruce_collisions == 0 then
|
||||
mcl_structures.call_struct(p, "ice_spike_large")
|
||||
mcl_structures.call_struct(p, "ice_spike_large", nil, pr)
|
||||
end
|
||||
elseif spike < 100 then
|
||||
-- Check surface
|
||||
|
@ -1471,7 +1509,7 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
local spruce_collisions = minetest.find_nodes_in_area({x=p.x+1,y=p.y+1,z=p.z+1}, {x=p.x+6, y=p.y+6, z=p.z+6}, {"mcl_core:sprucetree", "mcl_core:spruceleaves"})
|
||||
|
||||
if #surface >= 25 and #spruce_collisions == 0 then
|
||||
mcl_structures.call_struct(p, "ice_spike_small")
|
||||
mcl_structures.call_struct(p, "ice_spike_small", nil, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1479,36 +1517,31 @@ local function generate_structures(minp, maxp, seed, biomemap)
|
|||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end end
|
||||
-- End exit portal
|
||||
elseif minp.y <= END_EXIT_PORTAL_POS.y and maxp.y >= END_EXIT_PORTAL_POS.y and
|
||||
minp.x <= END_EXIT_PORTAL_POS.x and maxp.x >= END_EXIT_PORTAL_POS.x and
|
||||
minp.z <= END_EXIT_PORTAL_POS.z and maxp.z >= END_EXIT_PORTAL_POS.z then
|
||||
local built = false
|
||||
elseif minp.y <= END_EXIT_PORTAL_POS.y and maxp.y >= END_EXIT_PORTAL_POS.y and
|
||||
minp.x <= END_EXIT_PORTAL_POS.x and maxp.x >= END_EXIT_PORTAL_POS.x and
|
||||
minp.z <= END_EXIT_PORTAL_POS.z and maxp.z >= END_EXIT_PORTAL_POS.z then
|
||||
for y=maxp.y, minp.y, -1 do
|
||||
local p = {x=END_EXIT_PORTAL_POS.x, y=y, z=END_EXIT_PORTAL_POS.z}
|
||||
if minetest.get_node(p).name == "mcl_end:end_stone" then
|
||||
mcl_structures.call_struct(p, "end_exit_portal")
|
||||
built = true
|
||||
break
|
||||
return
|
||||
end
|
||||
end
|
||||
if not built then
|
||||
mcl_structures.call_struct(END_EXIT_PORTAL_POS, "end_exit_portal")
|
||||
end
|
||||
mcl_structures.call_struct(END_EXIT_PORTAL_POS, "end_exit_portal")
|
||||
end
|
||||
end
|
||||
|
||||
-- Buffers for LuaVoxelManip
|
||||
local lvm_buffer = {}
|
||||
local lvm_buffer_param2 = {}
|
||||
-- local lvm_buffer = {}
|
||||
-- local lvm_buffer_param2 = {}
|
||||
|
||||
-- Generate tree decorations in the bounding box. This adds:
|
||||
-- * Cocoa at jungle trees
|
||||
-- * Jungle tree vines
|
||||
-- * Oak vines in swamplands
|
||||
local function generate_tree_decorations(minp, maxp, seed, data, param2_data, area, biomemap, lvm_used)
|
||||
local function generate_tree_decorations(minp, maxp, seed, data, param2_data, area, biomemap, lvm_used, pr)
|
||||
if maxp.y < 0 then
|
||||
return lvm_used
|
||||
end
|
||||
|
@ -1576,7 +1609,7 @@ local function generate_tree_decorations(minp, maxp, seed, data, param2_data, ar
|
|||
|
||||
if minetest.find_node_near(pos, 1, {"mcl_core:jungleleaves"}) then
|
||||
|
||||
dir = math.random(1, cocoachance)
|
||||
dir = pr:next(1, cocoachance)
|
||||
|
||||
if dir == 1 then
|
||||
pos.z = pos.z + 1
|
||||
|
@ -1594,7 +1627,7 @@ local function generate_tree_decorations(minp, maxp, seed, data, param2_data, ar
|
|||
if dir < 5
|
||||
and data[p_pos] == c_air
|
||||
and l ~= nil and l > 12 then
|
||||
local c = math.random(1, 3)
|
||||
local c = pr:next(1, 3)
|
||||
if c == 1 then
|
||||
data[p_pos] = c_cocoa_1
|
||||
elseif c == 2 then
|
||||
|
@ -1810,125 +1843,206 @@ local generate_nether_decorations = function(minp, maxp, seed)
|
|||
|
||||
end
|
||||
|
||||
-- Below the bedrock, generate air/void
|
||||
minetest.register_on_generated(function(minp, maxp, seed)
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data(lvm_buffer)
|
||||
local param2_data = vm:get_param2_data(lvm_buffer_param2)
|
||||
local area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
|
||||
local aream = VoxelArea:new({MinEdge={x=minp.x, y=0, z=minp.z}, MaxEdge={x=maxp.x, y=0, z=maxp.z}})
|
||||
local lvm_used = false
|
||||
local biomemap
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed)
|
||||
add_chunk(minp)
|
||||
local p1, p2 = {x=minp.x, y=minp.y, z=minp.z}, {x=maxp.x, y=maxp.y, z=maxp.z}
|
||||
if lvm > 0 then
|
||||
local lvm_used, shadow = false, false
|
||||
local lb = {} -- buffer
|
||||
local lb2 = {} -- param2
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local e1, e2 = {x=emin.x, y=emin.y, z=emin.z}, {x=emax.x, y=emax.y, z=emax.z}
|
||||
local data2
|
||||
local data = vm:get_data(lb)
|
||||
if param2 > 0 then
|
||||
data2 = vm:get_param2_data(lb2)
|
||||
end
|
||||
local area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
|
||||
|
||||
local ymin, ymax
|
||||
for _, rec in pairs(mcl_mapgen_core.registered_generators) do
|
||||
if rec.vf then
|
||||
local lvm_used0, shadow0 = rec.vf(vm, data, data2, e1, e2, area, p1, p2, blockseed)
|
||||
if lvm_used0 then
|
||||
lvm_used = true
|
||||
end
|
||||
if shadow0 then
|
||||
shadow = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Generate basic layer-based nodes: void, bedrock, realm barrier, lava seas, etc.
|
||||
-- Also perform some basic node replacements.
|
||||
if lvm_used then
|
||||
-- Write stuff
|
||||
vm:set_data(data)
|
||||
if param2 > 0 then
|
||||
vm:set_param2_data(data2)
|
||||
end
|
||||
vm:calc_lighting(p1, p2, shadow)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
end
|
||||
end
|
||||
|
||||
-- Helper function to set all nodes in the layers between min and max.
|
||||
-- content_id: Node to set
|
||||
-- check: optional.
|
||||
-- If content_id, node will be set only if it is equal to check.
|
||||
-- If function(pos_to_check, content_id_at_this_pos), will set node only if returns true.
|
||||
-- min, max: Minimum and maximum Y levels of the layers to set
|
||||
-- minp, maxp: minp, maxp of the on_generated
|
||||
-- lvm_used: Set to true if any node in this on_generated has been set before.
|
||||
--
|
||||
-- returns true if any node was set and lvm_used otherwise
|
||||
local function set_layers(content_id, check, min, max, minp, maxp, lvm_used)
|
||||
if (maxp.y >= min and minp.y <= max) then
|
||||
for y = math.max(min, minp.y), math.min(max, maxp.y) do
|
||||
for x = minp.x, maxp.x do
|
||||
for z = minp.z, maxp.z do
|
||||
local p_pos = area:index(x, y, z)
|
||||
if check then
|
||||
if type(check) == "function" and check({x=x,y=y,z=z}, data[p_pos]) then
|
||||
data[p_pos] = content_id
|
||||
lvm_used = true
|
||||
elseif check == data[p_pos] then
|
||||
data[p_pos] = content_id
|
||||
lvm_used = true
|
||||
end
|
||||
else
|
||||
if nodes > 0 then
|
||||
for _, rec in pairs(mcl_mapgen_core.registered_generators) do
|
||||
if rec.nf then
|
||||
rec.nf(p1, p2, blockseed)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- add_chunk(minp)
|
||||
end)
|
||||
|
||||
minetest.register_on_generated=function(node_function)
|
||||
mcl_mapgen_core.register_generator("mod_"..tostring(#mcl_mapgen_core.registered_generators+1), nil, node_function)
|
||||
end
|
||||
|
||||
function mcl_mapgen_core.register_generator(id, lvm_function, node_function, priority, needs_param2)
|
||||
if not id then return end
|
||||
|
||||
local priority = priority or 5000
|
||||
|
||||
if lvm_function then lvm = lvm + 1 end
|
||||
if lvm_function then nodes = nodes + 1 end
|
||||
if needs_param2 then param2 = param2 + 1 end
|
||||
|
||||
local new_record = {
|
||||
i = priority,
|
||||
vf = lvm_function,
|
||||
nf = node_function,
|
||||
needs_param2 = needs_param2,
|
||||
}
|
||||
|
||||
mcl_mapgen_core.registered_generators[id] = new_record
|
||||
table.sort(
|
||||
mcl_mapgen_core.registered_generators,
|
||||
function(a, b)
|
||||
return (a.i < b.i) or ((a.i == b.i) and (a.vf ~= nil) and (b.vf == nil))
|
||||
end)
|
||||
end
|
||||
|
||||
function mcl_mapgen_core.unregister_generator(id)
|
||||
if not mcl_mapgen_core.registered_generators[id] then return end
|
||||
local rec = mcl_mapgen_core.registered_generators[id]
|
||||
mcl_mapgen_core.registered_generators[id] = nil
|
||||
if rec.vf then lvm = lvm - 1 end
|
||||
if rev.nf then nodes = nodes - 1 end
|
||||
if rec.needs_param2 then param2 = param2 - 1 end
|
||||
if rec.needs_level0 then level0 = level0 - 1 end
|
||||
end
|
||||
|
||||
-- Generate basic layer-based nodes: void, bedrock, realm barrier, lava seas, etc.
|
||||
-- Also perform some basic node replacements.
|
||||
|
||||
local bedrock_check
|
||||
if mcl_vars.mg_bedrock_is_rough then
|
||||
bedrock_check = function(pos, _, pr)
|
||||
local y = pos.y
|
||||
-- Bedrock layers with increasing levels of roughness, until a perfecly flat bedrock later at the bottom layer
|
||||
-- This code assumes a bedrock height of 5 layers.
|
||||
|
||||
local diff = mcl_vars.mg_bedrock_overworld_max - y -- Overworld bedrock
|
||||
local ndiff1 = mcl_vars.mg_bedrock_nether_bottom_max - y -- Nether bedrock, bottom
|
||||
local ndiff2 = mcl_vars.mg_bedrock_nether_top_max - y -- Nether bedrock, ceiling
|
||||
|
||||
local top
|
||||
if diff == 0 or ndiff1 == 0 or ndiff2 == 4 then
|
||||
-- 50% bedrock chance
|
||||
top = 2
|
||||
elseif diff == 1 or ndiff1 == 1 or ndiff2 == 3 then
|
||||
-- 66.666...%
|
||||
top = 3
|
||||
elseif diff == 2 or ndiff1 == 2 or ndiff2 == 2 then
|
||||
-- 75%
|
||||
top = 4
|
||||
elseif diff == 3 or ndiff1 == 3 or ndiff2 == 1 then
|
||||
-- 90%
|
||||
top = 10
|
||||
elseif diff == 4 or ndiff1 == 4 or ndiff2 == 0 then
|
||||
-- 100%
|
||||
return true
|
||||
else
|
||||
-- Not in bedrock layer
|
||||
return false
|
||||
end
|
||||
|
||||
return pr:next(1, top) <= top-1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Helper function to set all nodes in the layers between min and max.
|
||||
-- content_id: Node to set
|
||||
-- check: optional.
|
||||
-- If content_id, node will be set only if it is equal to check.
|
||||
-- If function(pos_to_check, content_id_at_this_pos), will set node only if returns true.
|
||||
-- min, max: Minimum and maximum Y levels of the layers to set
|
||||
-- minp, maxp: minp, maxp of the on_generated
|
||||
-- lvm_used: Set to true if any node in this on_generated has been set before.
|
||||
--
|
||||
-- returns true if any node was set and lvm_used otherwise
|
||||
local function set_layers(data, area, content_id, check, min, max, minp, maxp, lvm_used, pr)
|
||||
if (maxp.y >= min and minp.y <= max) then
|
||||
for y = math.max(min, minp.y), math.min(max, maxp.y) do
|
||||
for x = minp.x, maxp.x do
|
||||
for z = minp.z, maxp.z do
|
||||
local p_pos = area:index(x, y, z)
|
||||
if check then
|
||||
if type(check) == "function" and check({x=x,y=y,z=z}, data[p_pos], pr) then
|
||||
data[p_pos] = content_id
|
||||
lvm_used = true
|
||||
elseif check == data[p_pos] then
|
||||
data[p_pos] = content_id
|
||||
lvm_used = true
|
||||
end
|
||||
else
|
||||
data[p_pos] = content_id
|
||||
lvm_used = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return lvm_used
|
||||
end
|
||||
return lvm_used
|
||||
end
|
||||
|
||||
-- Below the bedrock, generate air/void
|
||||
local function basic(vm, data, data2, emin, emax, area, minp, maxp, blockseed)
|
||||
local biomemap, ymin, ymax
|
||||
local lvm_used = false
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
-- The Void
|
||||
lvm_used = set_layers(c_void, nil, -31000, mcl_vars.mg_nether_min-1, minp, maxp, lvm_used)
|
||||
lvm_used = set_layers(c_void, nil, mcl_vars.mg_nether_max+1, mcl_vars.mg_end_min-1, minp, maxp, lvm_used)
|
||||
lvm_used = set_layers(c_void, nil, mcl_vars.mg_end_max+1, mcl_vars.mg_realm_barrier_overworld_end_min-1, minp, maxp, lvm_used)
|
||||
lvm_used = set_layers(c_void, nil, mcl_vars.mg_realm_barrier_overworld_end_max+1, mcl_vars.mg_overworld_min-1, minp, maxp, lvm_used)
|
||||
|
||||
lvm_used = set_layers(data, area, c_void , nil, mcl_vars.mapgen_edge_min , mcl_vars.mg_nether_min -1, minp, maxp, lvm_used, pr)
|
||||
lvm_used = set_layers(data, area, c_void , nil, mcl_vars.mg_nether_max +1, mcl_vars.mg_end_min -1, minp, maxp, lvm_used, pr)
|
||||
lvm_used = set_layers(data, area, c_void , nil, mcl_vars.mg_end_max +1, mcl_vars.mg_realm_barrier_overworld_end_min-1, minp, maxp, lvm_used, pr)
|
||||
-- Realm barrier between the Overworld void and the End
|
||||
lvm_used = set_layers(c_realm_barrier, nil, mcl_vars.mg_realm_barrier_overworld_end_min, mcl_vars.mg_realm_barrier_overworld_end_max, minp, maxp, lvm_used)
|
||||
lvm_used = set_layers(data, area, c_realm_barrier, nil, mcl_vars.mg_realm_barrier_overworld_end_min , mcl_vars.mg_realm_barrier_overworld_end_max , minp, maxp, lvm_used, pr)
|
||||
lvm_used = set_layers(data, area, c_void , nil, mcl_vars.mg_realm_barrier_overworld_end_max+1, mcl_vars.mg_overworld_min -1, minp, maxp, lvm_used, pr)
|
||||
|
||||
if mg_name ~= "singlenode" then
|
||||
-- Bedrock
|
||||
local bedrock_check
|
||||
if mcl_vars.mg_bedrock_is_rough then
|
||||
bedrock_check = function(pos)
|
||||
local y = pos.y
|
||||
-- Bedrock layers with increasing levels of roughness, until a perfecly flat bedrock later at the bottom layer
|
||||
-- This code assumes a bedrock height of 5 layers.
|
||||
|
||||
local diff = mcl_vars.mg_bedrock_overworld_max - y -- Overworld bedrock
|
||||
local ndiff1 = mcl_vars.mg_bedrock_nether_bottom_max - y -- Nether bedrock, bottom
|
||||
local ndiff2 = mcl_vars.mg_bedrock_nether_top_max - y -- Nether bedrock, ceiling
|
||||
|
||||
local top
|
||||
if diff == 0 or ndiff1 == 0 or ndiff2 == 4 then
|
||||
-- 50% bedrock chance
|
||||
top = 2
|
||||
elseif diff == 1 or ndiff1 == 1 or ndiff2 == 3 then
|
||||
-- 66.666...%
|
||||
top = 3
|
||||
elseif diff == 2 or ndiff1 == 2 or ndiff2 == 2 then
|
||||
-- 75%
|
||||
top = 4
|
||||
elseif diff == 3 or ndiff1 == 3 or ndiff2 == 1 then
|
||||
-- 90%
|
||||
top = 10
|
||||
elseif diff == 4 or ndiff1 == 4 or ndiff2 == 0 then
|
||||
-- 100%
|
||||
return true
|
||||
else
|
||||
-- Not in bedrock layer
|
||||
return false
|
||||
end
|
||||
|
||||
return math.random(1, top) <= top-1
|
||||
end
|
||||
else
|
||||
bedrock_check = nil
|
||||
end
|
||||
|
||||
lvm_used = set_layers(c_bedrock, bedrock_check, mcl_vars.mg_bedrock_overworld_min, mcl_vars.mg_bedrock_overworld_max, minp, maxp, lvm_used)
|
||||
lvm_used = set_layers(c_bedrock, bedrock_check, mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_bottom_max, minp, maxp, lvm_used)
|
||||
lvm_used = set_layers(c_bedrock, bedrock_check, mcl_vars.mg_bedrock_nether_top_min, mcl_vars.mg_bedrock_nether_top_max, minp, maxp, lvm_used)
|
||||
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_vars.mg_bedrock_overworld_min, mcl_vars.mg_bedrock_overworld_max, minp, maxp, lvm_used, pr)
|
||||
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_bottom_max, minp, maxp, lvm_used, pr)
|
||||
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_vars.mg_bedrock_nether_top_min, mcl_vars.mg_bedrock_nether_top_max, minp, maxp, lvm_used, pr)
|
||||
|
||||
-- Flat Nether
|
||||
if mg_name == "flat" then
|
||||
lvm_used = set_layers(c_air, nil, mcl_vars.mg_flat_nether_floor, mcl_vars.mg_flat_nether_ceiling, minp, maxp, lvm_used)
|
||||
lvm_used = set_layers(data, area, c_air, nil, mcl_vars.mg_flat_nether_floor, mcl_vars.mg_flat_nether_ceiling, minp, maxp, lvm_used, pr)
|
||||
end
|
||||
|
||||
-- Big lava seas by replacing air below a certain height
|
||||
if mcl_vars.mg_lava then
|
||||
lvm_used = set_layers(c_lava, c_air, mcl_vars.mg_overworld_min, mcl_vars.mg_lava_overworld_max, emin, emax, lvm_used)
|
||||
lvm_used = set_layers(c_nether_lava, c_air, mcl_vars.mg_nether_min, mcl_vars.mg_lava_nether_max, emin, emax, lvm_used)
|
||||
lvm_used = set_layers(data, area, c_lava, c_air, mcl_vars.mg_overworld_min, mcl_vars.mg_lava_overworld_max, emin, emax, lvm_used, pr)
|
||||
lvm_used = set_layers(data, area, c_nether_lava, c_air, mcl_vars.mg_nether_min, mcl_vars.mg_lava_nether_max, emin, emax, lvm_used, pr)
|
||||
end
|
||||
|
||||
-- Clay, vines, cocoas
|
||||
lvm_used = generate_clay(minp, maxp, seed, data, area, lvm_used)
|
||||
lvm_used = generate_clay(minp, maxp, blockseed, data, area, lvm_used)
|
||||
|
||||
biomemap = minetest.get_mapgen_object("biomemap")
|
||||
lvm_used = generate_tree_decorations(minp, maxp, seed, data, param2_data, area, biomemap, lvm_used)
|
||||
lvm_used = generate_tree_decorations(minp, maxp, blockseed, data, data2, area, biomemap, lvm_used, pr)
|
||||
|
||||
----- Interactive block fixing section -----
|
||||
----- The section to perform basic block overrides of the core mapgen generated world. -----
|
||||
|
@ -1974,19 +2088,21 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
|||
-- Set param2 (=color) of grass blocks.
|
||||
-- Clear snowy grass blocks without snow above to ensure consistency.
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:dirt_with_grass", "mcl_core:dirt_with_grass_snow"})
|
||||
|
||||
-- Flat area at y=0 to read biome 3 times faster than 5.3.0.get_biome_data(pos).biome: 43us vs 125us per iteration:
|
||||
local aream = VoxelArea:new({MinEdge={x=minp.x, y=0, z=minp.z}, MaxEdge={x=maxp.x, y=0, z=maxp.z}})
|
||||
for n=1, #nodes do
|
||||
local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z)
|
||||
local p_pos_above = area:index(nodes[n].x, nodes[n].y+1, nodes[n].z)
|
||||
local p_pos_below = area:index(nodes[n].x, nodes[n].y-1, nodes[n].z)
|
||||
local b_pos = aream:index(nodes[n].x, 0, nodes[n].z)
|
||||
local n = nodes[n]
|
||||
local p_pos = area:index(n.x, n.y, n.z)
|
||||
local p_pos_above = area:index(n.x, n.y+1, n.z)
|
||||
local p_pos_below = area:index(n.x, n.y-1, n.z)
|
||||
local b_pos = aream:index(n.x, 0, n.z)
|
||||
local bn = minetest.get_biome_name(biomemap[b_pos])
|
||||
if bn then
|
||||
local biome = minetest.registered_biomes[bn]
|
||||
if biome then
|
||||
if biome._mcl_biome_type then
|
||||
param2_data[p_pos] = biome._mcl_palette_index
|
||||
lvm_used = true
|
||||
end
|
||||
if biome and biome._mcl_biome_type then
|
||||
data2[p_pos] = biome._mcl_palette_index
|
||||
lvm_used = true
|
||||
end
|
||||
end
|
||||
if data[p_pos] == c_dirt_with_grass_snow and p_pos_above and data[p_pos_above] ~= c_top_snow and data[p_pos_above] ~= c_snow_block then
|
||||
|
@ -1994,6 +2110,7 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
|||
lvm_used = true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Nether block fixes:
|
||||
|
@ -2025,27 +2142,28 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
|||
-- * Remove stone, sand, dirt in v6 so our End map generator works in v6.
|
||||
-- * Generate spawn platform (End portal destination)
|
||||
elseif emin.y <= mcl_vars.mg_end_max and emax.y >= mcl_vars.mg_end_min then
|
||||
local nodes
|
||||
local nodes, node
|
||||
if mg_name == "v6" then
|
||||
nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
|
||||
else
|
||||
nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source"})
|
||||
end
|
||||
for n=1, #nodes do
|
||||
local y = nodes[n].y
|
||||
local p_pos = area:index(nodes[n].x, y, nodes[n].z)
|
||||
|
||||
if data[p_pos] == c_water or data[p_pos] == c_stone or data[p_pos] == c_dirt or data[p_pos] == c_sand then
|
||||
data[p_pos] = c_air
|
||||
lvm_used = true
|
||||
if #nodes > 0 then
|
||||
lvm_used = true
|
||||
for n=1, #nodes do
|
||||
node = nodes[n]
|
||||
data[area:index(node.x, node.y, node.z)] = c_air
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Obsidian spawn platform
|
||||
if minp.y <= mcl_vars.mg_end_platform_pos.y and maxp.y >= mcl_vars.mg_end_platform_pos.y and
|
||||
minp.x <= mcl_vars.mg_end_platform_pos.x and maxp.x >= mcl_vars.mg_end_platform_pos.z and
|
||||
minp.z <= mcl_vars.mg_end_platform_pos.z and maxp.z >= mcl_vars.mg_end_platform_pos.z then
|
||||
minp.x <= mcl_vars.mg_end_platform_pos.x and maxp.x >= mcl_vars.mg_end_platform_pos.z and
|
||||
minp.z <= mcl_vars.mg_end_platform_pos.z and maxp.z >= mcl_vars.mg_end_platform_pos.z then
|
||||
|
||||
local pos1 = {x = math.max(minp.x, mcl_vars.mg_end_platform_pos.x-2), y = math.max(minp.y, mcl_vars.mg_end_platform_pos.y), z = math.max(minp.z, mcl_vars.mg_end_platform_pos.z-2)}
|
||||
local pos2 = {x = math.min(maxp.x, mcl_vars.mg_end_platform_pos.x+2), y = math.min(maxp.y, mcl_vars.mg_end_platform_pos.y+2), z = math.min(maxp.z, mcl_vars.mg_end_platform_pos.z+2)}
|
||||
|
||||
for x=math.max(minp.x, mcl_vars.mg_end_platform_pos.x-2), math.min(maxp.x, mcl_vars.mg_end_platform_pos.x+2) do
|
||||
for z=math.max(minp.z, mcl_vars.mg_end_platform_pos.z-2), math.min(maxp.z, mcl_vars.mg_end_platform_pos.z+2) do
|
||||
for y=math.max(minp.y, mcl_vars.mg_end_platform_pos.y), math.min(maxp.y, mcl_vars.mg_end_platform_pos.y+2) do
|
||||
|
@ -2065,7 +2183,7 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
|||
|
||||
-- Final hackery: Set sun light level in the End.
|
||||
-- -26912 is at a mapchunk border.
|
||||
local shadow
|
||||
local shadow = true
|
||||
if minp.y >= -26912 and maxp.y <= mcl_vars.mg_end_max then
|
||||
vm:set_lighting({day=15, night=15})
|
||||
lvm_used = true
|
||||
|
@ -2075,21 +2193,60 @@ minetest.register_on_generated(function(minp, maxp, seed)
|
|||
lvm_used = true
|
||||
end
|
||||
|
||||
-- Write stuff
|
||||
if lvm_used then
|
||||
vm:set_data(data)
|
||||
vm:set_param2_data(param2_data)
|
||||
vm:calc_lighting(nil, nil, shadow)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
end
|
||||
|
||||
if mg_name ~= "singlenode" then
|
||||
-- Generate special decorations
|
||||
generate_underground_mushrooms(minp, maxp, seed)
|
||||
generate_nether_decorations(minp, maxp, seed)
|
||||
generate_structures(minp, maxp, seed, biomemap)
|
||||
generate_underground_mushrooms(minp, maxp, blockseed)
|
||||
generate_nether_decorations(minp, maxp, blockseed)
|
||||
generate_structures(minp, maxp, blockseed, biomemap)
|
||||
end
|
||||
end)
|
||||
|
||||
return lvm_used, shadow
|
||||
end
|
||||
|
||||
mcl_mapgen_core.register_generator("main", basic, nil, 1, true)
|
||||
|
||||
-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like 5.3.0 does.
|
||||
-- p: Position, if it's wrong, {name="error"} node will return.
|
||||
-- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
|
||||
-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
|
||||
--
|
||||
-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
|
||||
function mcl_mapgen_core.get_node(p, force, us_timeout)
|
||||
-- check initial circumstances
|
||||
if not p or not p.x or not p.y or not p.z then return {name="error"} end
|
||||
|
||||
-- try common way
|
||||
local node = minetest.get_node(p)
|
||||
if node.name ~= "ignore" then
|
||||
return node
|
||||
end
|
||||
|
||||
-- copy table to get sure it won't changed by other threads
|
||||
local pos = {x=p.x,y=p.y,z=p.z}
|
||||
|
||||
-- try LVM
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" or not force then
|
||||
return node
|
||||
end
|
||||
|
||||
-- all ways failed - need to emerge (or forceload if generated)
|
||||
local us_timeout = us_timeout or 244
|
||||
if mcl_mapgen_core.is_generated(pos) then
|
||||
minetest.forceload_block(pos)
|
||||
else
|
||||
minetest.emerge_area(pos, pos)
|
||||
end
|
||||
|
||||
local t = minetest.get_us_time()
|
||||
|
||||
node = minetest.get_node(pos)
|
||||
|
||||
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
|
||||
return node
|
||||
-- it still can return "ignore", LOL, even if force = true, but only after time out
|
||||
end
|
||||
|
|
|
@ -67,7 +67,8 @@ local init_strongholds = function()
|
|||
end
|
||||
|
||||
-- Stronghold generation for register_on_generated.
|
||||
local generate_strongholds = function(minp, maxp)
|
||||
local generate_strongholds = function(minp, maxp, blockseed)
|
||||
local pr = PseudoRandom(blockseed)
|
||||
for s=1, #strongholds do
|
||||
if not strongholds[s].generated then
|
||||
local pos = strongholds[s].pos
|
||||
|
@ -80,6 +81,12 @@ local generate_strongholds = function(minp, maxp)
|
|||
if pos.x + 6 > maxp.x then
|
||||
pos.x = maxp.x - 7
|
||||
end
|
||||
if pos.y - 4 < minp.y then
|
||||
pos.y = minp.y + 5
|
||||
end
|
||||
if pos.y + 4 > maxp.y then
|
||||
pos.y = maxp.y - 5
|
||||
end
|
||||
if pos.z - 6 < minp.z then
|
||||
pos.z = minp.z + 7
|
||||
end
|
||||
|
@ -87,7 +94,7 @@ local generate_strongholds = function(minp, maxp)
|
|||
pos.z = maxp.z - 7
|
||||
end
|
||||
|
||||
mcl_structures.call_struct(pos, "end_portal_shrine")
|
||||
mcl_structures.call_struct(pos, "end_portal_shrine", nil, pr)
|
||||
strongholds[s].generated = true
|
||||
end
|
||||
end
|
||||
|
@ -96,9 +103,4 @@ end
|
|||
|
||||
init_strongholds()
|
||||
|
||||
--[[ Note this mod depends on mcl_mapgen_core to make sure the core mapgen runs FIRST.
|
||||
This is important because we need this to make sure the stronghold isn't instantly
|
||||
overwritten by the core mapgen (since it uses LuaVoxelManip). ]]
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed)
|
||||
generate_strongholds(minp, maxp)
|
||||
end)
|
||||
mcl_mapgen_core.register_generator("strongholds", nil, generate_strongholds, 999999)
|
||||
|
|
|
@ -1,24 +1,58 @@
|
|||
local S = minetest.get_translator("mcl_structures")
|
||||
mcl_structures ={}
|
||||
local rotations = {
|
||||
"0",
|
||||
"90",
|
||||
"180",
|
||||
"270"
|
||||
}
|
||||
|
||||
mcl_structures.minetest_place_schematic = minetest.place_schematic
|
||||
local function ecb_place(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
mcl_structures.minetest_place_schematic(param.pos, param.schematic, param.rotation, param.replacements, param.force_placement, param.flags)
|
||||
if param.after_placement_callback and param.p1 and param.p2 then
|
||||
param.after_placement_callback(param.p1, param.p2, param.size, param.rotation, param.pr)
|
||||
end
|
||||
end
|
||||
minetest.place_schematic = function(pos, schematic, rotation, replacements, force_placement, flags, after_placement_callback, pr)
|
||||
local s = loadstring(minetest.serialize_schematic(schematic, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return(schematic)")()
|
||||
if s and s.size then
|
||||
local x, z = s.size.x, s.size.z
|
||||
if rotation then
|
||||
if rotation == "random" and pr then
|
||||
rotation = rotations[pr:next(1,#rotations)]
|
||||
end
|
||||
if rotation == "random" then
|
||||
x = math.max(x, z)
|
||||
z = x
|
||||
elseif rotation == "90" or rotation == "270" then
|
||||
x, z = z, x
|
||||
end
|
||||
end
|
||||
local p1 = {x=pos.x , y=pos.y , z=pos.z }
|
||||
local p2 = {x=pos.x+x-1, y=pos.y+s.size.y-1, z=pos.z+z-1}
|
||||
minetest.log("verbose","[mcl_structures] size=" ..minetest.pos_to_string(s.size) .. ", rotation=" .. tostring(rotation) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
local param = {pos=vector.new(pos), schematic=s, rotation=rotation, replacements=replacements, force_placement=force_placement, flags=flags, p1=p1, p2=p2, after_placement_callback = after_placement_callback, size=vector.new(s.size), pr=pr}
|
||||
minetest.emerge_area(p1, p2, ecb_place, param)
|
||||
end
|
||||
end
|
||||
mcl_structures.place_schematic = minetest.place_schematic -- for direct usage
|
||||
|
||||
mcl_structures.get_struct = function(file)
|
||||
local localfile = minetest.get_modpath("mcl_structures").."/schematics/"..file
|
||||
local file, errorload = io.open(localfile, "rb")
|
||||
if errorload ~= nil then
|
||||
minetest.log("error", '[mcl_structures] Could not open this struct: ' .. localfile)
|
||||
return nil
|
||||
minetest.log("error", '[mcl_structures] Could not open this struct: ' .. localfile)
|
||||
return nil
|
||||
end
|
||||
|
||||
local allnode = file:read("*a")
|
||||
file:close()
|
||||
local allnode = file:read("*a")
|
||||
file:close()
|
||||
|
||||
return allnode
|
||||
return allnode
|
||||
end
|
||||
|
||||
local mapseed = tonumber(minetest.get_mapgen_setting("seed"))
|
||||
-- Random number generator for all generated structures
|
||||
local pr = PseudoRandom(mapseed)
|
||||
|
||||
-- Call on_construct on pos.
|
||||
-- Useful to init chests from formspec.
|
||||
local init_node_construct = function(pos)
|
||||
|
@ -32,16 +66,17 @@ local init_node_construct = function(pos)
|
|||
end
|
||||
|
||||
-- The call of Struct
|
||||
mcl_structures.call_struct = function(pos, struct_style, rotation)
|
||||
mcl_structures.call_struct = function(pos, struct_style, rotation, pr)
|
||||
minetest.log("action","[mcl_structures] call_struct " .. struct_style.." at "..minetest.pos_to_string(pos))
|
||||
if not rotation then
|
||||
rotation = "random"
|
||||
end
|
||||
if struct_style == "desert_temple" then
|
||||
return mcl_structures.generate_desert_temple(pos, rotation)
|
||||
return mcl_structures.generate_desert_temple(pos, rotation, pr)
|
||||
elseif struct_style == "desert_well" then
|
||||
return mcl_structures.generate_desert_well(pos, rotation)
|
||||
elseif struct_style == "igloo" then
|
||||
return mcl_structures.generate_igloo(pos, rotation)
|
||||
return mcl_structures.generate_igloo(pos, rotation, pr)
|
||||
elseif struct_style == "witch_hut" then
|
||||
return mcl_structures.generate_witch_hut(pos, rotation)
|
||||
elseif struct_style == "ice_spike_small" then
|
||||
|
@ -49,13 +84,13 @@ mcl_structures.call_struct = function(pos, struct_style, rotation)
|
|||
elseif struct_style == "ice_spike_large" then
|
||||
return mcl_structures.generate_ice_spike_large(pos, rotation)
|
||||
elseif struct_style == "boulder" then
|
||||
return mcl_structures.generate_boulder(pos, rotation)
|
||||
return mcl_structures.generate_boulder(pos, rotation, pr)
|
||||
elseif struct_style == "fossil" then
|
||||
return mcl_structures.generate_fossil(pos, rotation)
|
||||
return mcl_structures.generate_fossil(pos, rotation, pr)
|
||||
elseif struct_style == "end_exit_portal" then
|
||||
return mcl_structures.generate_end_exit_portal(pos, rotation)
|
||||
elseif struct_style == "end_portal_shrine" then
|
||||
return mcl_structures.generate_end_portal_shrine(pos, rotation)
|
||||
return mcl_structures.generate_end_portal_shrine(pos, rotation, pr)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -65,12 +100,12 @@ mcl_structures.generate_desert_well = function(pos)
|
|||
return minetest.place_schematic(newpos, path, "0", nil, true)
|
||||
end
|
||||
|
||||
mcl_structures.generate_igloo = function(pos)
|
||||
mcl_structures.generate_igloo = function(pos, rotation, pr)
|
||||
-- Place igloo
|
||||
local success, rotation = mcl_structures.generate_igloo_top(pos)
|
||||
local success, rotation = mcl_structures.generate_igloo_top(pos, pr)
|
||||
-- Place igloo basement with 50% chance
|
||||
local r = math.random(1,2)
|
||||
if success and r == 1 then
|
||||
local r = pr:next(1,2)
|
||||
if r == 1 then
|
||||
-- Select basement depth
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
local buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10)
|
||||
|
@ -86,7 +121,7 @@ mcl_structures.generate_igloo = function(pos)
|
|||
if buffer <= 19 then
|
||||
return success
|
||||
end
|
||||
local depth = math.random(19, buffer)
|
||||
local depth = pr:next(19, buffer)
|
||||
local bpos = {x=pos.x, y=pos.y-depth, z=pos.z}
|
||||
-- trapdoor position
|
||||
local tpos
|
||||
|
@ -111,8 +146,8 @@ mcl_structures.generate_igloo = function(pos)
|
|||
return success
|
||||
end
|
||||
local set_brick = function(pos)
|
||||
local c = math.random(1, 3) -- cracked chance
|
||||
local m = math.random(1, 10) -- chance for monster egg
|
||||
local c = pr:next(1, 3) -- cracked chance
|
||||
local m = pr:next(1, 10) -- chance for monster egg
|
||||
local brick
|
||||
if m == 1 then
|
||||
if c == 1 then
|
||||
|
@ -155,75 +190,74 @@ mcl_structures.generate_igloo = function(pos)
|
|||
minetest.set_node({x=tpos.x,y=tpos.y-y,z=tpos.z}, {name="mcl_core:ladder", param2=ladder_param2})
|
||||
end
|
||||
-- Place basement
|
||||
mcl_structures.generate_igloo_basement(bpos, rotation)
|
||||
mcl_structures.generate_igloo_basement(bpos, rotation, pr)
|
||||
end
|
||||
return success
|
||||
end
|
||||
|
||||
mcl_structures.generate_igloo_top = function(pos)
|
||||
mcl_structures.generate_igloo_top = function(pos, pr)
|
||||
-- FIXME: This spawns bookshelf instead of furnace. Fix this!
|
||||
-- Furnace does ot work atm because apparently meta is not set. :-(
|
||||
local newpos = {x=pos.x,y=pos.y-1,z=pos.z}
|
||||
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_igloo_top.mts"
|
||||
local rotation = tostring(math.random(0,3)*90)
|
||||
local rotation = tostring(pr:next(0,3)*90)
|
||||
return minetest.place_schematic(newpos, path, rotation, nil, true), rotation
|
||||
end
|
||||
|
||||
mcl_structures.generate_igloo_basement = function(pos, orientation)
|
||||
local function igloo_placement_callback(p1, p2, size, orientation, pr)
|
||||
local chest_offset
|
||||
if orientation == "0" then
|
||||
chest_offset = {x=5, y=1, z=5}
|
||||
elseif orientation == "90" then
|
||||
chest_offset = {x=5, y=1, z=3}
|
||||
elseif orientation == "180" then
|
||||
chest_offset = {x=3, y=1, z=1}
|
||||
elseif orientation == "270" then
|
||||
chest_offset = {x=1, y=1, z=5}
|
||||
else
|
||||
return
|
||||
end
|
||||
local size = {x=9,y=5,z=7}
|
||||
local lootitems = mcl_loot.get_multi_loot({
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 1,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:apple_gold", weight = 1 },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 8,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:coal_lump", weight = 15, amount_min = 1, amount_max = 4 },
|
||||
{ itemstring = "mcl_core:apple", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_farming:wheat_item", weight = 10, amount_min = 2, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 10, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 10 },
|
||||
{ itemstring = "mcl_tools:axe_stone", weight = 2 },
|
||||
{ itemstring = "mcl_core:emerald", weight = 1 },
|
||||
}
|
||||
}}, pr)
|
||||
|
||||
local chest_pos = vector.add(p1, chest_offset)
|
||||
init_node_construct(chest_pos)
|
||||
local meta = minetest.get_meta(chest_pos)
|
||||
local inv = meta:get_inventory()
|
||||
mcl_loot.fill_inventory(inv, "main", lootitems)
|
||||
end
|
||||
|
||||
mcl_structures.generate_igloo_basement = function(pos, orientation, pr)
|
||||
-- TODO: Add brewing stand
|
||||
-- TODO: Add monster eggs
|
||||
-- TODO: Spawn villager and zombie villager
|
||||
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_igloo_basement.mts"
|
||||
|
||||
local success = minetest.place_schematic(pos, path, orientation, nil, true)
|
||||
if success then
|
||||
local chest_offset
|
||||
if orientation == "0" then
|
||||
chest_offset = {x=5, y=1, z=5}
|
||||
elseif orientation == "90" then
|
||||
chest_offset = {x=5, y=1, z=3}
|
||||
elseif orientation == "180" then
|
||||
chest_offset = {x=3, y=1, z=1}
|
||||
elseif orientation == "270" then
|
||||
chest_offset = {x=1, y=1, z=5}
|
||||
else
|
||||
return success
|
||||
end
|
||||
local size = {x=9,y=5,z=7}
|
||||
local lootitems = mcl_loot.get_multi_loot({
|
||||
{
|
||||
stacks_min = 1,
|
||||
stacks_max = 1,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:apple_gold", weight = 1 },
|
||||
}
|
||||
},
|
||||
{
|
||||
stacks_min = 2,
|
||||
stacks_max = 8,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:coal_lump", weight = 15, amount_min = 1, amount_max = 4 },
|
||||
{ itemstring = "mcl_core:apple", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_farming:wheat_item", weight = 10, amount_min = 2, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:gold_nugget", weight = 10, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 10 },
|
||||
{ itemstring = "mcl_tools:axe_stone", weight = 2 },
|
||||
{ itemstring = "mcl_core:emerald", weight = 1 },
|
||||
}
|
||||
}}, pr)
|
||||
|
||||
local chest_pos = vector.add(pos, chest_offset)
|
||||
init_node_construct(chest_pos)
|
||||
local meta = minetest.get_meta(chest_pos)
|
||||
local inv = meta:get_inventory()
|
||||
mcl_loot.fill_inventory(inv, "main", lootitems)
|
||||
end
|
||||
return success
|
||||
mcl_structures.place_schematic(pos, path, orientation, nil, true, nil, igloo_placement_callback, pr)
|
||||
end
|
||||
|
||||
mcl_structures.generate_boulder = function(pos)
|
||||
mcl_structures.generate_boulder = function(pos, rotation, pr)
|
||||
-- Choose between 2 boulder sizes (2×2×2 or 3×3×3)
|
||||
local r = math.random(1, 10)
|
||||
local r = pr:next(1, 10)
|
||||
local path
|
||||
if r <= 3 then
|
||||
path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_boulder_small.mts"
|
||||
|
@ -235,9 +269,20 @@ mcl_structures.generate_boulder = function(pos)
|
|||
return minetest.place_schematic(newpos, path)
|
||||
end
|
||||
|
||||
local function hut_placement_callback(p1, p2, size, orientation, pr)
|
||||
if not p1 or not p2 then return end
|
||||
local legs = minetest.find_nodes_in_area(p1, p2, "mcl_core:tree")
|
||||
for i = 1, #legs do
|
||||
while minetest.get_item_group(mcl_mapgen_core.get_node({x=legs[i].x, y=legs[i].y-1, z=legs[i].z}, true, 333333).name, "water") ~= 0 do
|
||||
legs[i].y = legs[i].y - 1
|
||||
minetest.swap_node(legs[i], {name = "mcl_core:tree", param2 = 2})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mcl_structures.generate_witch_hut = function(pos, rotation)
|
||||
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_witch_hut.mts"
|
||||
return minetest.place_schematic(pos, path, rotation, nil, true)
|
||||
mcl_structures.place_schematic(pos, path, rotation, nil, true, nil, hut_placement_callback, pr)
|
||||
end
|
||||
|
||||
mcl_structures.generate_ice_spike_small = function(pos)
|
||||
|
@ -250,7 +295,7 @@ mcl_structures.generate_ice_spike_large = function(pos)
|
|||
return minetest.place_schematic(pos, path, "random", nil, false)
|
||||
end
|
||||
|
||||
mcl_structures.generate_fossil = function(pos)
|
||||
mcl_structures.generate_fossil = function(pos, rotation, pr)
|
||||
-- Generates one out of 8 possible fossil pieces
|
||||
local newpos = {x=pos.x,y=pos.y-1,z=pos.z}
|
||||
local fossils = {
|
||||
|
@ -263,7 +308,7 @@ mcl_structures.generate_fossil = function(pos)
|
|||
"mcl_structures_fossil_spine_3.mts", -- 7×4×13
|
||||
"mcl_structures_fossil_spine_4.mts", -- 8×5×13
|
||||
}
|
||||
local r = math.random(1, #fossils)
|
||||
local r = pr:next(1, #fossils)
|
||||
local path = minetest.get_modpath("mcl_structures").."/schematics/"..fossils[r]
|
||||
return minetest.place_schematic(newpos, path, "random", nil, true)
|
||||
end
|
||||
|
@ -273,24 +318,16 @@ mcl_structures.generate_end_exit_portal = function(pos)
|
|||
return minetest.place_schematic(pos, path, "0", nil, true)
|
||||
end
|
||||
|
||||
local generate_end_portal_shrine_no_delay = function(newpos)
|
||||
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_portal_room_simple.mts"
|
||||
local size = {x=13, y=8, z=13}
|
||||
local ret = minetest.place_schematic(newpos, path, "0", nil, true)
|
||||
if ret == nil then
|
||||
return ret
|
||||
end
|
||||
|
||||
local area_start, area_end = newpos, vector.add(newpos, size)
|
||||
local function shrine_placement_callback(p1, p2, size, rotation, pr)
|
||||
-- Find and setup spawner with silverfish
|
||||
local spawners = minetest.find_nodes_in_area(area_start, area_end, "mcl_mobspawners:spawner")
|
||||
local spawners = minetest.find_nodes_in_area(p1, p2, "mcl_mobspawners:spawner")
|
||||
for s=1, #spawners do
|
||||
local meta = minetest.get_meta(spawners[s])
|
||||
mcl_mobspawners.setup_spawner(spawners[s], "mobs_mc:silverfish")
|
||||
end
|
||||
|
||||
-- Shuffle stone brick types
|
||||
local bricks = minetest.find_nodes_in_area(area_start, area_end, "mcl_core:stonebrick")
|
||||
local bricks = minetest.find_nodes_in_area(p1, p2, "mcl_core:stonebrick")
|
||||
for b=1, #bricks do
|
||||
local r_bricktype = pr:next(1, 100)
|
||||
local r_infested = pr:next(1, 100)
|
||||
|
@ -317,7 +354,7 @@ local generate_end_portal_shrine_no_delay = function(newpos)
|
|||
end
|
||||
|
||||
-- Also replace stairs
|
||||
local stairs = minetest.find_nodes_in_area(area_start, area_end, {"mcl_stairs:stair_stonebrick", "mcl_stairs:stair_stonebrick_outer", "mcl_stairs:stair_stonebrick_inner"})
|
||||
local stairs = minetest.find_nodes_in_area(p1, p2, {"mcl_stairs:stair_stonebrick", "mcl_stairs:stair_stonebrick_outer", "mcl_stairs:stair_stonebrick_inner"})
|
||||
for s=1, #stairs do
|
||||
local stair = minetest.get_node(stairs[s])
|
||||
local r_type = pr:next(1, 100)
|
||||
|
@ -344,7 +381,7 @@ local generate_end_portal_shrine_no_delay = function(newpos)
|
|||
end
|
||||
|
||||
-- Randomly add ender eyes into end portal frames, but never fill the entire frame
|
||||
local frames = minetest.find_nodes_in_area(area_start, area_end, "mcl_portals:end_portal_frame")
|
||||
local frames = minetest.find_nodes_in_area(p1, p2, "mcl_portals:end_portal_frame")
|
||||
local eyes = 0
|
||||
for f=1, #frames do
|
||||
local r_eye = pr:next(1, 10)
|
||||
|
@ -357,40 +394,34 @@ local generate_end_portal_shrine_no_delay = function(newpos)
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
local function ecb_generate_end_portal_shrine(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining <= 0 then
|
||||
generate_end_portal_shrine_no_delay({x=param.x, y=param.y, z=param.z})
|
||||
end
|
||||
end
|
||||
|
||||
mcl_structures.generate_end_portal_shrine = function(pos)
|
||||
local offset = {x=6, y=8, z=6}
|
||||
mcl_structures.generate_end_portal_shrine = function(pos, rotation, pr)
|
||||
local offset = {x=6, y=4, z=6}
|
||||
local size = {x=13, y=8, z=13}
|
||||
local newpos = { x = pos.x - offset.x, y = pos.y, z = pos.z - offset.z }
|
||||
minetest.emerge_area(vector.subtract(newpos,10), vector.add(vector.add(newpos, size),10), ecb_generate_end_portal_shrine, {x=newpos.x, y=newpos.y, z=newpos.z})
|
||||
|
||||
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_portal_room_simple.mts"
|
||||
mcl_structures.place_schematic(newpos, path, "0", nil, true, nil, shrine_placement_callback, pr)
|
||||
end
|
||||
|
||||
mcl_structures.generate_desert_temple = function(pos)
|
||||
-- No Generating for the temple ... Why using it ? No Change
|
||||
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_desert_temple.mts"
|
||||
local newpos = {x=pos.x,y=pos.y-12,z=pos.z}
|
||||
local size = {x=22, y=24, z=22}
|
||||
if newpos == nil then
|
||||
return
|
||||
end
|
||||
local ret = minetest.place_schematic(newpos, path, "random", nil, true)
|
||||
if ret == nil then
|
||||
return ret
|
||||
local function temple_placement_callback(p1, p2, size, rotation, pr)
|
||||
|
||||
-- Delete cacti leftovers:
|
||||
local cactus_nodes = minetest.find_nodes_in_area_under_air(p1, p2, "mcl_core:cactus")
|
||||
if cactus_nodes and #cactus_nodes > 0 then
|
||||
for _, pos in pairs(cactus_nodes) do
|
||||
local node_below = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z})
|
||||
if node_below and node_below.name == "mcl_core:sandstone" then
|
||||
minetest.swap_node(pos, {name="air"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Find chests.
|
||||
-- FIXME: Searching this large area just for the chets is not efficient. Need a better way to find the chests;
|
||||
-- probably let's just infer it from newpos because the schematic always the same.
|
||||
local chests = minetest.find_nodes_in_area({x=newpos.x-size.x, y=newpos.y, z=newpos.z-size.z}, vector.add(newpos, size), "mcl_chests:chest")
|
||||
local chests = minetest.find_nodes_in_area(p1, p2, "mcl_chests:chest")
|
||||
|
||||
-- Add desert temple loot into chests
|
||||
for c=1, #chests do
|
||||
|
@ -436,7 +467,7 @@ mcl_structures.generate_desert_temple = function(pos)
|
|||
end
|
||||
|
||||
-- Initialize pressure plates and randomly remove up to 5 plates
|
||||
local pplates = minetest.find_nodes_in_area({x=newpos.x-size.x, y=newpos.y, z=newpos.z-size.z}, vector.add(newpos, size), "mesecons_pressureplates:pressure_plate_stone_off")
|
||||
local pplates = minetest.find_nodes_in_area(p1, p2, "mesecons_pressureplates:pressure_plate_stone_off")
|
||||
local pplates_remove = 5
|
||||
for p=1, #pplates do
|
||||
if pplates_remove > 0 and pr:next(1, 100) >= 50 then
|
||||
|
@ -448,8 +479,17 @@ mcl_structures.generate_desert_temple = function(pos)
|
|||
minetest.registered_nodes["mesecons_pressureplates:pressure_plate_stone_off"].on_construct(pplates[p])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
mcl_structures.generate_desert_temple = function(pos, rotation, pr)
|
||||
-- No Generating for the temple ... Why using it ? No Change
|
||||
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_desert_temple.mts"
|
||||
local newpos = {x=pos.x,y=pos.y-12,z=pos.z}
|
||||
local size = {x=22, y=24, z=22}
|
||||
if newpos == nil then
|
||||
return
|
||||
end
|
||||
minetest.place_schematic(newpos, path, "random", nil, true, nil, temple_placement_callback, pr)
|
||||
end
|
||||
|
||||
local registered_structures = {}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
-------------------------------------------------------------------------------
|
||||
function settlements.build_schematic(vm, data, va, pos, building, replace_wall, name)
|
||||
-- get building node material for better integration to surrounding
|
||||
local platform_material = mcl_util.get_far_node(pos, true)
|
||||
if not platform_material then
|
||||
local platform_material = mcl_mapgen_core.get_node(pos)
|
||||
if not platform_material or (platform_material.name == "air" or platform_material.name == "ignore") then
|
||||
return
|
||||
end
|
||||
platform_material = platform_material.name
|
||||
|
@ -81,12 +81,15 @@ function settlements.create_site_plan(maxp, minp, pr)
|
|||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
-- find center of chunk
|
||||
local center = {
|
||||
x=maxp.x-half_map_chunk_size,
|
||||
x=math.floor((minp.x+maxp.x)/2),
|
||||
y=maxp.y,
|
||||
z=maxp.z-half_map_chunk_size
|
||||
z=math.floor((minp.z+maxp.z)/2)
|
||||
}
|
||||
-- find center_surface of chunk
|
||||
local center_surface , surface_material = settlements.find_surface(center)
|
||||
local center_surface , surface_material = settlements.find_surface(center, true)
|
||||
local chunks = {}
|
||||
chunks[mcl_vars.get_chunk_number(center)] = true
|
||||
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
|
||||
|
@ -114,49 +117,57 @@ function settlements.create_site_plan(maxp, minp, pr)
|
|||
local x, z, r = center_surface.x, center_surface.z, building_all_info["hsize"]
|
||||
-- draw j circles around center and increase radius by math.random(2,5)
|
||||
for j = 1,20 do
|
||||
if number_built < number_of_buildings then
|
||||
-- set position on imaginary circle
|
||||
for j = 0, 360, 15 do
|
||||
local angle = j * math.pi / 180
|
||||
local ptx, ptz = x + r * math.cos( angle ), z + r * math.sin( angle )
|
||||
ptx = settlements.round(ptx, 0)
|
||||
ptz = settlements.round(ptz, 0)
|
||||
local pos1 = { x=ptx, y=center_surface.y+50, z=ptz}
|
||||
local pos_surface, surface_material = settlements.find_surface(pos1)
|
||||
if not pos_surface then break end
|
||||
-- set position on imaginary circle
|
||||
for j = 0, 360, 15 do
|
||||
local angle = j * math.pi / 180
|
||||
local ptx, ptz = x + r * math.cos( angle ), z + r * math.sin( angle )
|
||||
ptx = settlements.round(ptx, 0)
|
||||
ptz = settlements.round(ptz, 0)
|
||||
local pos1 = { x=ptx, y=center_surface.y+50, z=ptz}
|
||||
local chunk_number = mcl_vars.get_chunk_number(pos1)
|
||||
local pos_surface, surface_material
|
||||
if chunks[chunk_number] then
|
||||
pos_surface, surface_material = settlements.find_surface(pos1)
|
||||
else
|
||||
chunks[chunk_number] = true
|
||||
pos_surface, surface_material = settlements.find_surface(pos1, true)
|
||||
end
|
||||
if not pos_surface then break end
|
||||
|
||||
local randomized_schematic_table = shuffle(settlements.schematic_table, pr)
|
||||
-- pick schematic
|
||||
local size = #randomized_schematic_table
|
||||
for i = size, 1, -1 do
|
||||
-- already enough buildings of that type?
|
||||
if count_buildings[randomized_schematic_table[i]["name"]] < randomized_schematic_table[i]["max_num"]*number_of_buildings then
|
||||
building_all_info = randomized_schematic_table[i]
|
||||
-- check distance to other buildings
|
||||
local distance_to_other_buildings_ok = settlements.check_distance(settlement_info, pos_surface, building_all_info["hsize"])
|
||||
if distance_to_other_buildings_ok then
|
||||
-- count built houses
|
||||
count_buildings[building_all_info["name"]] = count_buildings[building_all_info["name"]] +1
|
||||
rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
number_built = number_built + 1
|
||||
settlement_info[index] = {
|
||||
pos = pos_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
index = index + 1
|
||||
break
|
||||
end
|
||||
local randomized_schematic_table = shuffle(settlements.schematic_table, pr)
|
||||
-- pick schematic
|
||||
local size = #randomized_schematic_table
|
||||
for i = size, 1, -1 do
|
||||
-- already enough buildings of that type?
|
||||
if count_buildings[randomized_schematic_table[i]["name"]] < randomized_schematic_table[i]["max_num"]*number_of_buildings then
|
||||
building_all_info = randomized_schematic_table[i]
|
||||
-- check distance to other buildings
|
||||
local distance_to_other_buildings_ok = settlements.check_distance(settlement_info, pos_surface, building_all_info["hsize"])
|
||||
if distance_to_other_buildings_ok then
|
||||
-- count built houses
|
||||
count_buildings[building_all_info["name"]] = count_buildings[building_all_info["name"]] +1
|
||||
rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
number_built = number_built + 1
|
||||
settlement_info[index] = {
|
||||
pos = pos_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
index = index + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
if number_of_buildings == number_built then
|
||||
break
|
||||
end
|
||||
end
|
||||
r = r + pr:next(2,5)
|
||||
if number_of_buildings == number_built then
|
||||
break
|
||||
end
|
||||
end
|
||||
if number_built >= number_of_buildings then
|
||||
break
|
||||
end
|
||||
r = r + pr:next(2,5)
|
||||
end
|
||||
settlements.debug("really ".. number_built)
|
||||
return settlement_info
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mcl_util
|
||||
mcl_mapgen_core
|
||||
mcl_core
|
||||
mcl_loot
|
||||
mcl_farming?
|
||||
|
|
|
@ -51,11 +51,12 @@ function settlements.terraform(settlement_info, pr)
|
|||
settlements.ground(p, pr)
|
||||
else
|
||||
-- write ground
|
||||
local p = {x=pos.x+xi, y=pos.y+yi, z=pos.z+zi}
|
||||
local node = mcl_util.get_far_node(p, true)
|
||||
if node and node.name ~= "air" then
|
||||
minetest.swap_node(p,{name="air"})
|
||||
end
|
||||
-- local p = {x=pos.x+xi, y=pos.y+yi, z=pos.z+zi}
|
||||
-- local node = mcl_mapgen_core.get_node(p)
|
||||
-- if node and node.name ~= "air" then
|
||||
-- minetest.swap_node(p,{name="air"})
|
||||
-- end
|
||||
minetest.swap_node({x=pos.x+xi, y=pos.y+yi, z=pos.z+zi},{name="air"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -52,7 +52,7 @@ end
|
|||
--
|
||||
-- on map generation, try to build a settlement
|
||||
--
|
||||
local function build_a_settlement_no_delay(minp, maxp, blockseed)
|
||||
local function build_a_settlement(minp, maxp, blockseed)
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
-- fill settlement_info with buildings and their data
|
||||
|
@ -72,30 +72,28 @@ local function build_a_settlement_no_delay(minp, maxp, blockseed)
|
|||
settlements.initialize_nodes(settlement_info, pr)
|
||||
end
|
||||
|
||||
local function ecb_build_a_settlement(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining <= 0 then
|
||||
build_a_settlement_no_delay(param.minp, param.maxp, param.blockseed)
|
||||
end
|
||||
local function ecb_village(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
local minp, maxp, blockseed = param.minp, param.maxp, param.blockseed
|
||||
build_a_settlement(minp, maxp, blockseed)
|
||||
end
|
||||
|
||||
-- Disable natural generation in singlenode.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if mg_name ~= "singlenode" then
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed)
|
||||
-- needed for manual and automated settlement building
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
|
||||
-- randomly try to build settlements
|
||||
if blockseed % 77 ~= 17 then return end
|
||||
|
||||
mcl_mapgen_core.register_generator("villages", nil, function(minp, maxp, blockseed)
|
||||
-- don't build settlement underground
|
||||
if maxp.y < 0 then return end
|
||||
|
||||
-- randomly try to build settlements
|
||||
if blockseed % 77 ~= 17 then return end
|
||||
-- needed for manual and automated settlement building
|
||||
-- don't build settlements on (too) uneven terrain
|
||||
local height_difference = settlements.evaluate_heightmap(minp, maxp)
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
local height_difference = settlements.evaluate_heightmap()
|
||||
if height_difference > max_height_difference then return end
|
||||
-- we need 'minetest.after' here to exit from emerging thread we probably currently in:
|
||||
minetest.after(0.1, build_a_settlement_no_delay, vector.new(minp), vector.new(maxp), blockseed)
|
||||
|
||||
local param={minp=vector.new(minp), maxp=vector.new(maxp), blockseed=blockseed}
|
||||
minetest.emerge_area(minp, maxp, ecb_village, param)
|
||||
end)
|
||||
end
|
||||
-- manually place villages
|
||||
|
@ -108,7 +106,7 @@ if minetest.is_creative_enabled("") then
|
|||
if not pointed_thing.under then return end
|
||||
local minp = vector.subtract( pointed_thing.under, half_map_chunk_size)
|
||||
local maxp = vector.add( pointed_thing.under, half_map_chunk_size)
|
||||
build_a_settlement_no_delay(minp, maxp, math.random(0,32767))
|
||||
build_a_settlement(minp, maxp, math.random(0,32767))
|
||||
end
|
||||
})
|
||||
end
|
||||
|
|
|
@ -45,31 +45,27 @@ end
|
|||
-- function to find surface block y coordinate
|
||||
-- returns surface postion
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.find_surface(pos)
|
||||
function settlements.find_surface(pos, wait)
|
||||
local p6 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local itter -- count up or down
|
||||
local itter = 1 -- count up or down
|
||||
local cnt_max = 200
|
||||
-- check, in which direction to look for surface
|
||||
local surface_node = mcl_util.get_far_node(p6, true)
|
||||
if surface_node and string.find(surface_node.name,"air") then
|
||||
itter = -1
|
||||
local surface_node
|
||||
if wait then
|
||||
surface_node = mcl_mapgen_core.get_node(p6, true, 10000000)
|
||||
else
|
||||
itter = 1
|
||||
surface_node = mcl_mapgen_core.get_node(p6)
|
||||
end
|
||||
if surface_node.name=="air" or surface_node.name=="ignore" then
|
||||
itter = -1
|
||||
end
|
||||
-- go through nodes an find surface
|
||||
while cnt < cnt_max do
|
||||
cnt = cnt+1
|
||||
surface_node = mcl_util.get_far_node(p6, true)
|
||||
if surface_node.name == "ignore" then
|
||||
settlements.debug("find_surface1: nil or ignore")
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Check Surface_node and Node above
|
||||
--
|
||||
if settlements.surface_mat[surface_node.name] then
|
||||
local surface_node_plus_1 = mcl_util.get_far_node({ x=p6.x, y=p6.y+1, z=p6.z}, true)
|
||||
local surface_node_plus_1 = mcl_mapgen_core.get_node({ x=p6.x, y=p6.y+1, z=p6.z})
|
||||
if surface_node_plus_1 and surface_node and
|
||||
(string.find(surface_node_plus_1.name,"air") or
|
||||
string.find(surface_node_plus_1.name,"snow") or
|
||||
|
@ -93,6 +89,8 @@ function settlements.find_surface(pos)
|
|||
settlements.debug("find_surface4: y<0")
|
||||
return nil
|
||||
end
|
||||
cnt = cnt+1
|
||||
surface_node = mcl_mapgen_core.get_node(p6)
|
||||
end
|
||||
settlements.debug("find_surface5: cnt_max overflow")
|
||||
return nil
|
||||
|
@ -241,7 +239,7 @@ function settlements.initialize_nodes(settlement_info, pr)
|
|||
for xi = 0,width do
|
||||
for zi = 0,depth do
|
||||
local ptemp = {x=p.x+xi, y=p.y+yi, z=p.z+zi}
|
||||
local node = mcl_util.get_far_node(ptemp, true)
|
||||
local node = mcl_mapgen_core.get_node(ptemp)
|
||||
if node.name == "mcl_furnaces:furnace" or
|
||||
node.name == "mcl_chests:chest" or
|
||||
node.name == "mcl_anvils:anvil" then
|
||||
|
@ -272,44 +270,39 @@ end
|
|||
-- evaluate heightmap
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.evaluate_heightmap()
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
-- max height and min height, initialize with impossible values for easier first time setting
|
||||
local max_y = -50000
|
||||
local min_y = 50000
|
||||
-- only evaluate the center square of heightmap 40 x 40
|
||||
local square_start = 1621
|
||||
local square_end = 1661
|
||||
for j = 1 , 40, 1 do
|
||||
for i = square_start, square_end, 1 do
|
||||
-- skip buggy heightmaps, return high value
|
||||
if heightmap[i] == -31000 or
|
||||
heightmap[i] == 31000
|
||||
then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
if heightmap[i] < min_y
|
||||
then
|
||||
min_y = heightmap[i]
|
||||
end
|
||||
if heightmap[i] > max_y
|
||||
then
|
||||
max_y = heightmap[i]
|
||||
end
|
||||
end
|
||||
-- set next line
|
||||
square_start = square_start + 80
|
||||
square_end = square_end + 80
|
||||
end
|
||||
-- return the difference between highest and lowest pos in chunk
|
||||
local height_diff = max_y - min_y
|
||||
-- filter buggy heightmaps
|
||||
if height_diff <= 1
|
||||
then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
-- debug info
|
||||
settlements.debug("heightdiff ".. height_diff)
|
||||
return height_diff
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
-- max height and min height, initialize with impossible values for easier first time setting
|
||||
local max_y = -50000
|
||||
local min_y = 50000
|
||||
-- only evaluate the center square of heightmap 40 x 40
|
||||
local square_start = 1621
|
||||
local square_end = 1661
|
||||
for j = 1 , 40, 1 do
|
||||
for i = square_start, square_end, 1 do
|
||||
-- skip buggy heightmaps, return high value
|
||||
if heightmap[i] == -31000 or heightmap[i] == 31000 then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
if heightmap[i] < min_y then
|
||||
min_y = heightmap[i]
|
||||
end
|
||||
if heightmap[i] > max_y then
|
||||
max_y = heightmap[i]
|
||||
end
|
||||
end
|
||||
-- set next line
|
||||
square_start = square_start + 80
|
||||
square_end = square_end + 80
|
||||
end
|
||||
-- return the difference between highest and lowest pos in chunk
|
||||
local height_diff = max_y - min_y
|
||||
-- filter buggy heightmaps
|
||||
if height_diff <= 1 then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
-- debug info
|
||||
settlements.debug("heightdiff ".. height_diff)
|
||||
return height_diff
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
mcl_init
|
||||
mcl_worlds
|
||||
mcl_core
|
||||
mcl_mapgen_core
|
||||
mcl_loot
|
||||
mcl_tnt
|
||||
mcl_farming
|
||||
|
|
|
@ -1089,7 +1089,7 @@ local function create_corridor_system(main_cave_coords)
|
|||
end
|
||||
|
||||
-- The rail corridor algorithm starts here
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed)
|
||||
mcl_mapgen_core.register_generator("railcorridors", nil, function(minp, maxp, blockseed, _pr)
|
||||
-- We re-init the randomizer for every mapchunk as we start generating in the middle of each mapchunk.
|
||||
-- We can't use the mapgen seed as this would make the algorithm depending on the order the mapchunk generate.
|
||||
InitRandomizer(blockseed)
|
||||
|
@ -1115,4 +1115,4 @@ minetest.register_on_generated(function(minp, maxp, blockseed)
|
|||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end, 10)
|
||||
|
|
Loading…
Reference in a new issue