Update mapgen api to v3 from mcl5
parent
229f821758
commit
54ea8ba6b1
|
@ -22,10 +22,18 @@ local minetest_pos_to_string = minetest.pos_to_string
|
|||
mcl_mapgen.CS = math_max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
mcl_mapgen.BS = math_max(1, core.MAP_BLOCKSIZE or 16)
|
||||
mcl_mapgen.LIMIT = math_max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_mapgen.MAX_LIMIT = math_max(1, core.MAX_MAP_GENERATION_LIMIT or 31000) -- might be set to 31000 or removed, see https://github.com/minetest/minetest/issues/10428
|
||||
mcl_mapgen.MAX_LIMIT = 31000 -- MAX_MAP_GENERATION_LIMIT, https://github.com/minetest/minetest/issues/10428
|
||||
mcl_mapgen.OFFSET = - math_floor(mcl_mapgen.CS / 2)
|
||||
mcl_mapgen.OFFSET_NODES = mcl_mapgen.OFFSET * mcl_mapgen.BS
|
||||
mcl_mapgen.CS_NODES = mcl_mapgen.CS * mcl_mapgen.BS
|
||||
mcl_mapgen.LAST_BLOCK = mcl_mapgen.CS - 1
|
||||
mcl_mapgen.LAST_NODE_IN_BLOCK = mcl_mapgen.BS - 1
|
||||
mcl_mapgen.LAST_NODE_IN_CHUNK = mcl_mapgen.CS_NODES - 1
|
||||
mcl_mapgen.HALF_CS_NODES = math_floor(mcl_mapgen.CS_NODES / 2)
|
||||
mcl_mapgen.HALF_BS = math_floor(mcl_mapgen.BS / 2)
|
||||
mcl_mapgen.CS_3D = mcl_mapgen.CS^3
|
||||
mcl_mapgen.CHUNK_WITH_SHELL = mcl_mapgen.CS + 2
|
||||
mcl_mapgen.CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL^3
|
||||
|
||||
local central_chunk_min_pos = mcl_mapgen.OFFSET * mcl_mapgen.BS
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_mapgen.CS_NODES - 1
|
||||
|
@ -52,13 +60,14 @@ local seed = minetest.get_mapgen_setting("seed")
|
|||
mcl_mapgen.seed = seed
|
||||
mcl_mapgen.name = minetest.get_mapgen_setting("mg_name")
|
||||
mcl_mapgen.v6 = mcl_mapgen.name == "v6"
|
||||
mcl_mapgen.superflat = mcl_mapgen.name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
mcl_mapgen.flat = mcl_mapgen.name == "flat"
|
||||
mcl_mapgen.superflat = mcl_mapgen.flat and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
mcl_mapgen.singlenode = mcl_mapgen.name == "singlenode"
|
||||
mcl_mapgen.normal = not mcl_mapgen.superflat and not mcl_mapgen.singlenode
|
||||
local superflat, singlenode, normal = mcl_mapgen.superflat, mcl_mapgen.singlenode, mcl_mapgen.normal
|
||||
local flat, superflat, singlenode, normal = mcl_mapgen.flat, mcl_mapgen.superflat, mcl_mapgen.singlenode, mcl_mapgen.normal
|
||||
|
||||
minetest_log("action", "[mcl_mapgen] Mapgen mode: " .. (normal and "normal" or (superflat and "superflat" or "singlenode")))
|
||||
----------------------------------------------------------------------------------------------------------------------------
|
||||
minetest_log("action", "[mcl_mapgen] Mapgen mode: " .. (normal and "normal" or (superflat and "superflat" or (flat and "flat" or "singlenode"))))
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Generator queues
|
||||
local queue_unsafe_engine = {}
|
||||
|
@ -77,11 +86,15 @@ local nodes_chunk = 0
|
|||
local safe_functions = 0
|
||||
|
||||
local BS, CS = mcl_mapgen.BS, mcl_mapgen.CS -- Mapblock size (in nodes), Mapchunk size (in blocks)
|
||||
local LAST_BLOCK, LAST_NODE = CS - 1, BS - 1 -- First mapblock in chunk (node in mapblock) has number 0, last has THIS number. It's for runtime optimization
|
||||
local offset = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks)
|
||||
local CS_NODES = mcl_mapgen.CS_NODES -- 80
|
||||
|
||||
local CS_3D = CS * CS * CS
|
||||
local CS_NODES = mcl_mapgen.CS_NODES
|
||||
local LAST_BLOCK = mcl_mapgen.LAST_BLOCK
|
||||
local LAST_NODE_IN_BLOCK = mcl_mapgen.LAST_NODE_IN_BLOCK
|
||||
local LAST_NODE_IN_CHUNK = mcl_mapgen.LAST_NODE_IN_CHUNK
|
||||
local HALF_CS_NODES = mcl_mapgen.HALF_CS_NODES
|
||||
local CS_3D = mcl_mapgen.CS_3D
|
||||
local CHUNK_WITH_SHELL = mcl_mapgen.CHUNK_WITH_SHELL
|
||||
local CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL_3D
|
||||
|
||||
local DEFAULT_ORDER = order.DEFAULT
|
||||
|
||||
|
@ -89,21 +102,18 @@ function mcl_mapgen.register_on_generated(callback_function, order)
|
|||
queue_unsafe_engine[#queue_unsafe_engine+1] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_unsafe_engine, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
|
||||
function mcl_mapgen.register_mapgen(callback_function, order)
|
||||
nodes_chunk = nodes_chunk + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_chunks_nodes[nodes_chunk] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_chunks_nodes, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
|
||||
function mcl_mapgen.register_mapgen_lvm(callback_function, order)
|
||||
lvm_chunk = lvm_chunk + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_chunks_lvm[lvm_chunk] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_chunks_lvm, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
|
||||
function mcl_mapgen.register_mapgen_block(callback_function, order)
|
||||
block = block + 1
|
||||
nodes_block = nodes_block + 1
|
||||
|
@ -111,7 +121,6 @@ function mcl_mapgen.register_mapgen_block(callback_function, order)
|
|||
queue_blocks_nodes[nodes_block] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_blocks_nodes, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
|
||||
function mcl_mapgen.register_mapgen_block_lvm(callback_function, order)
|
||||
block = block + 1
|
||||
queue_blocks_lvm_counter = queue_blocks_lvm_counter + 1
|
||||
|
@ -120,25 +129,76 @@ function mcl_mapgen.register_mapgen_block_lvm(callback_function, order)
|
|||
table.sort(queue_blocks_lvm, function(a, b) return (a.order <= b.order) end)
|
||||
end
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
local blocks = minetest.deserialize(storage:get_string("mapgen_blocks") or "return {}") or {}
|
||||
local chunks = minetest.deserialize(storage:get_string("mapgen_chunks") or "return {}") or {}
|
||||
minetest.register_on_shutdown(function()
|
||||
storage:set_string("mapgen_chunks", minetest.serialize(chunks))
|
||||
storage:set_string("mapgen_blocks", minetest.serialize(blocks))
|
||||
end)
|
||||
|
||||
local vm_context -- here will be many references and flags, like: param2, light_data, heightmap, biomemap, heatmap, humiditymap, gennotify, write_lvm, write_param2, shadow
|
||||
local data, param2_data, light, area
|
||||
local current_blocks = {}
|
||||
local current_chunks = {}
|
||||
local lvm_buffer, lvm_param2_buffer, lvm_light_buffer = {}, {}, {} -- Static buffer pointers
|
||||
|
||||
local all_blocks_in_chunk = {}
|
||||
for x = -1, LAST_BLOCK+1 do
|
||||
for y = -1, LAST_BLOCK+1 do
|
||||
for z = -1, LAST_BLOCK+1 do
|
||||
all_blocks_in_chunk[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * y + z) + x] = vector.new(x, y, z)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local chunk_scan_range = {
|
||||
[-CS_NODES] = {-1 , -1 },
|
||||
[ 0 ] = {-1 , LAST_BLOCK+1},
|
||||
[ CS_NODES] = {LAST_BLOCK+1, LAST_BLOCK+1},
|
||||
}
|
||||
|
||||
local function is_chunk_finished(minp)
|
||||
local center = vector.add(minp, HALF_CS_NODES)
|
||||
for check_x = center.x - CS_NODES, center.x + CS_NODES, CS_NODES do
|
||||
for check_y = center.y - CS_NODES, center.y + CS_NODES, CS_NODES do
|
||||
for check_z = center.z - CS_NODES, center.z + CS_NODES, CS_NODES do
|
||||
local pos = vector.new(check_x, check_y, check_z)
|
||||
if pos ~= center then
|
||||
minetest_get_voxel_manip():read_from_map(pos, pos)
|
||||
local node = minetest_get_node(pos)
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function uint32_t(v)
|
||||
if v >= 0 then
|
||||
return v % 0x100000000
|
||||
end
|
||||
return 0x100000000 - (math.abs(v) % 0x100000000)
|
||||
end
|
||||
|
||||
local function get_block_seed(pos, current_seed)
|
||||
local current_seed = current_seed or uint32_t(tonumber(seed))
|
||||
return uint32_t(uint32_t(23 * pos.x) + uint32_t(42123 * pos.y) + uint32_t(38134234 * pos.z) + current_seed)
|
||||
end
|
||||
|
||||
local function get_block_seed2(pos, current_seed)
|
||||
local current_seed = current_seed or uint32_t(tonumber(seed))
|
||||
local n = uint32_t(uint32_t(1619 * pos.x) + uint32_t(31337 * pos.y) + uint32_t(52591 * pos.z) + uint32_t(1013 * current_seed))
|
||||
n = bit.bxor(bit.rshift(n, 13), n)
|
||||
local seed = uint32_t((n * uint32_t(n * n * 60493 + 19990303) + 1376312589))
|
||||
return seed
|
||||
end
|
||||
|
||||
local function get_block_seed3(pos, current_seed)
|
||||
local current_seed = uint32_t(current_seed or uint32_t(tonumber(seed)))
|
||||
local x = uint32_t((pos.x + 32768) * 13)
|
||||
local y = uint32_t((pos.y + 32767) * 13873)
|
||||
local z = uint32_t((pos.z + 76705) * 115249)
|
||||
local seed = uint32_t(bit.bxor(current_seed, x, y, z))
|
||||
return seed
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, chunkseed)
|
||||
local minp, maxp, chunkseed = minp, maxp, chunkseed
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
minetest_log("warning", "[mcl_mapgen] New_chunk=" .. minetest_pos_to_string(minp) .. "..." .. minetest_pos_to_string(maxp) .. ", shell=" .. minetest_pos_to_string(emin) .. "..." .. minetest_pos_to_string(emax) .. ", chunkseed=" .. tostring(chunkseed))
|
||||
|
||||
data = vm:get_data(lvm_buffer)
|
||||
area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
|
||||
vm_context = {
|
||||
|
@ -157,116 +217,71 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
|
|||
chunkseed = chunkseed,
|
||||
}
|
||||
|
||||
local current_blocks = {}
|
||||
local current_chunks = {}
|
||||
if safe_functions > 0 then
|
||||
local x0, y0, z0 = minp.x, minp.y, minp.z
|
||||
local bx0, by0, bz0 = math_floor(x0/BS), math_floor(y0/BS), math_floor(z0/BS)
|
||||
local bx1, by1, bz1 = bx0 + LAST_BLOCK, by0 + LAST_BLOCK, bz0 + LAST_BLOCK -- only for entire chunk check
|
||||
|
||||
-- Keep `chunkseed` in `chunks[cx][cy][cz].seed` for further safe usage:
|
||||
local cx0, cy0, cz0 = math_floor((bx0-offset)/CS), math_floor((by0-offset)/CS), math_floor((bz0-offset)/CS)
|
||||
if not chunks[cx0] then chunks[cx0] = {} end
|
||||
if not chunks[cx0][cy0] then chunks[cx0][cy0] = {} end
|
||||
if not chunks[cx0][cy0][cz0] then
|
||||
chunks[cx0][cy0][cz0] = {seed = chunkseed, counter = 0}
|
||||
local ready_blocks = table.copy(all_blocks_in_chunk)
|
||||
local p0 = vector.new(minp)
|
||||
local center = vector.add(p0, HALF_CS_NODES)
|
||||
for x = -CS_NODES, CS_NODES, CS_NODES do
|
||||
for y = -CS_NODES, CS_NODES, CS_NODES do
|
||||
for z = -CS_NODES, CS_NODES, CS_NODES do
|
||||
if x ~= 0 or y ~= 0 or z ~= 0 then
|
||||
local offset = vector.new(x, y, z)
|
||||
local pos = center + offset
|
||||
minetest_get_voxel_manip():read_from_map(pos, pos)
|
||||
local node = minetest_get_node(pos)
|
||||
local is_generated = node.name ~= "ignore"
|
||||
if is_generated then
|
||||
local adjacent_chunk_pos = p0 + offset
|
||||
if is_chunk_finished(adjacent_chunk_pos) then
|
||||
current_chunks[#current_chunks + 1] = adjacent_chunk_pos
|
||||
end
|
||||
else
|
||||
chunks[cx0][cy0][cz0].seed = chunkseed
|
||||
end
|
||||
|
||||
local x1, y1, z1, x2, y2, z2 = emin.x, emin.y, emin.z, emax.x, emax.y, emax.z
|
||||
local x, y, z = x1, y1, z1 -- iterate 7x7x7 mapchunk, {x,y,z} - first node pos. of mapblock
|
||||
local bx, by, bz -- block coords (in blocs)
|
||||
local box, boy, boz -- block offsets in chunks (in blocks)
|
||||
while x < x2 do
|
||||
bx = math_floor(x/BS)
|
||||
local block_pos_offset_removed = bx - offset
|
||||
local cx = math_floor(block_pos_offset_removed / CS)
|
||||
box = block_pos_offset_removed % CS
|
||||
if not blocks[bx] then blocks[bx]={} end
|
||||
|
||||
-- We don't know how many calls, including this one, will overwrite this block content!
|
||||
-- Start calculating it with `total_mapgen_block_writes_through_x` variable.
|
||||
-- It can be `8 or less`, if we (speaking of `x` axis) are on chunk edge now,
|
||||
-- or it can be `4 or less` - if we are in the middle of the chunk by `x` axis:
|
||||
|
||||
local total_mapgen_block_writes_through_x = (box > 0 and box < LAST_BLOCK) and 4 or 8
|
||||
while y < y2 do
|
||||
by = math_floor(y/BS)
|
||||
block_pos_offset_removed = by - offset
|
||||
local cy = math_floor(block_pos_offset_removed / CS)
|
||||
boy = block_pos_offset_removed % CS
|
||||
if not blocks[bx][by] then blocks[bx][by]={} end
|
||||
|
||||
-- Here we just divide `total_mapgen_block_writes_through_x` by 2,
|
||||
-- if we are (speaking of `y` axis now) in the middle of the chunk now.
|
||||
-- Or we don't divide it, if not.
|
||||
-- So, basing on `total_mapgen_block_writes_through_x`,
|
||||
--- we calculate `total_mapgen_block_writes_through_y` this way:
|
||||
|
||||
local total_mapgen_block_writes_through_y = (boy > 0 and boy < LAST_BLOCK) and math_floor(total_mapgen_block_writes_through_x / 2) or total_mapgen_block_writes_through_x
|
||||
while z < z2 do
|
||||
bz = math_floor(z/BS)
|
||||
block_pos_offset_removed = bz - offset
|
||||
local cz = math_floor(block_pos_offset_removed / CS)
|
||||
boz = block_pos_offset_removed % CS
|
||||
|
||||
-- Now we do absolutely the same for `z` axis, basing on our previous result
|
||||
-- from `total_mapgen_block_writes_through_y` variable.
|
||||
-- And our final result is in `total_mapgen_block_writes`.
|
||||
-- It can be still 8, derived from `x` calculation, but it can be less!
|
||||
-- It can be even 1, if we are in safe 3x3x3 area of mapchunk:
|
||||
|
||||
local total_mapgen_block_writes = (boz > 0 and boz < LAST_BLOCK) and math_floor(total_mapgen_block_writes_through_y / 2) or total_mapgen_block_writes_through_y
|
||||
|
||||
-- Get current number of writes from the table, or just set it to 1, if accessing first time:
|
||||
|
||||
local current_mapgen_block_writes = blocks[bx][by][bz] and (blocks[bx][by][bz] + 1) or 1
|
||||
|
||||
-- And compare:
|
||||
|
||||
if current_mapgen_block_writes == total_mapgen_block_writes then
|
||||
-- this block shouldn't be overwritten anymore, no need to keep it in memory
|
||||
blocks[bx][by][bz] = nil
|
||||
if not chunks[cx] then chunks[cx] = {} end
|
||||
if not chunks[cx][cy] then chunks[cx][cy] = {} end
|
||||
if not chunks[cx][cy][cz] then
|
||||
if not chunks[cx][cy][cz] then chunks[cx][cy][cz] = {counter = 1} end
|
||||
else
|
||||
chunks[cx][cy][cz].counter = chunks[cx][cy][cz].counter + 1
|
||||
if chunks[cx][cy][cz].counter >= CS_3D then
|
||||
current_chunks[#current_chunks+1] = { x = cx, y = cy, z = cz, s = chunks[cx][cy][cz].seed }
|
||||
-- this chunk shouldn't be overwritten anymore, no need to keep it in memory
|
||||
chunks[cx][cy][cz] = nil
|
||||
if next(chunks[cx][cy]) == nil then chunks[cx][cy] = nil end
|
||||
if next(chunks[cx]) == nil then chunks[cx] = nil end
|
||||
local scan_range_x = chunk_scan_range[x]
|
||||
for cut_x = scan_range_x[1], scan_range_x[2] do
|
||||
local scan_range_y = chunk_scan_range[y]
|
||||
for cut_y = scan_range_y[1], scan_range_y[2] do
|
||||
local scan_range_z = chunk_scan_range[z]
|
||||
for cut_z = scan_range_z[1], scan_range_z[2] do
|
||||
ready_blocks[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * cut_y + cut_z) + cut_x] = nil
|
||||
end
|
||||
end
|
||||
local blockseed = seed + bx * 7 + by * 243 + bz * 11931
|
||||
if queue_blocks_lvm_counter > 0 then
|
||||
vm_context.blockseed = blockseed
|
||||
vm_context.minp, vm_context.maxp = {x=x, y=y, z=z}, {x=x+LAST_NODE, y=y+LAST_NODE, z=z+LAST_NODE}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local number_of_blocks = 0
|
||||
for k, offset in pairs(ready_blocks) do
|
||||
if queue_blocks_lvm_counter > 0 or nodes_block > 0 then
|
||||
local block_minp = p0 + vector.multiply(offset, BS)
|
||||
local block_maxp = vector.add(block_minp, LAST_NODE_IN_BLOCK)
|
||||
local blockseed = get_block_seed3(block_minp)
|
||||
vm_context.minp, vm_context.maxp, vm_context.blockseed = block_minp, block_maxp, blockseed
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_block_lvm(function(vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_blocks_lvm) do
|
||||
v.callback_function(vm_context)
|
||||
end
|
||||
end
|
||||
if nodes_block > 0 then
|
||||
current_blocks[#current_blocks+1] = { minp = {x=x, y=y, z=z}, maxp = {x=x+LAST_NODE, y=y+LAST_NODE, z=z+LAST_NODE}, seed = blockseed }
|
||||
current_blocks[#current_blocks + 1] = { minp = block_minp, maxp = block_maxp, blockseed = blockseed }
|
||||
end
|
||||
else
|
||||
blocks[bx][by][bz] = current_mapgen_block_writes
|
||||
end
|
||||
z = z + BS
|
||||
number_of_blocks = number_of_blocks + 1
|
||||
end
|
||||
if next(blocks[bx][by]) == nil then blocks[bx][by] = nil end
|
||||
z = z1
|
||||
y = y + BS
|
||||
end
|
||||
if next(blocks[bx]) == nil then blocks[bx] = nil end
|
||||
y = y1
|
||||
x = x + BS
|
||||
if number_of_blocks == CHUNK_WITH_SHELL_3D then
|
||||
current_chunks[#current_chunks + 1] = p0
|
||||
end
|
||||
end
|
||||
|
||||
if #queue_unsafe_engine > 0 then
|
||||
vm_context.minp, vm_context.maxp = minp, maxp
|
||||
-- * U N S A F E --
|
||||
-- mcl_mapgen.register_on_generated(function(vm_context), order_number) --
|
||||
-- * U N S A F E --
|
||||
for _, v in pairs(queue_unsafe_engine) do
|
||||
v.f(vm_context)
|
||||
end
|
||||
|
@ -280,7 +295,7 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
|
|||
vm:set_light_data(light)
|
||||
end
|
||||
if vm_context.write or vm_context.write_param2 or vm_context.write_light then
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true) -- TODO: check boundaries
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
elseif vm_context.calc_lighting then
|
||||
|
@ -288,12 +303,9 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
|
|||
end
|
||||
end
|
||||
|
||||
for i, b in pairs(current_chunks) do
|
||||
local cx, cy, cz, seed = b.x, b.y, b.z, b.s
|
||||
local bx, by, bz = cx * CS + offset, cy * CS + offset, cz * CS + offset
|
||||
local x, y, z = bx * BS, by * BS, bz * BS
|
||||
local minp = {x = x, y = y, z = z}
|
||||
local maxp = {x = x + CS_NODES - 1, y = y + CS_NODES - 1, z = z + CS_NODES - 1}
|
||||
for i, chunk_minp in pairs(current_chunks) do
|
||||
local chunk_maxp = vector.add(chunk_minp, LAST_NODE_IN_CHUNK)
|
||||
local current_chunk_seed = get_block_seed3(vector.subtract(chunk_minp, BS))
|
||||
area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp})
|
||||
vm_context = {
|
||||
data = data,
|
||||
|
@ -303,17 +315,23 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
|
|||
lvm_buffer = lvm_buffer,
|
||||
lvm_param2_buffer = lvm_param2_buffer,
|
||||
lvm_light_buffer = lvm_light_buffer,
|
||||
emin = minp,
|
||||
emax = maxp,
|
||||
minp = minp,
|
||||
maxp = maxp,
|
||||
chunkseed = seed,
|
||||
emin = chunk_minp,
|
||||
emax = chunk_maxp,
|
||||
minp = chunk_minp,
|
||||
maxp = chunk_maxp,
|
||||
chunkseed = current_chunk_seed,
|
||||
}
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_lvm(function(vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_chunks_lvm) do
|
||||
vm_context = v.f(vm_context)
|
||||
end
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen(function(minp, maxp, chunkseed, vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_chunks_nodes) do
|
||||
v.f(minp, maxp, seed, vm_context)
|
||||
v.f(chunk_minp, chunk_maxp, current_chunk_seed, vm_context)
|
||||
end
|
||||
if vm_context.write or vm_context.write_param2 or vm_context.write_light then
|
||||
if vm_context.write then
|
||||
|
@ -332,14 +350,15 @@ minetest.register_on_generated(function(minp, maxp, chunkseed)
|
|||
elseif vm_context.calc_lighting then
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true)
|
||||
end
|
||||
current_chunks[i] = nil
|
||||
end
|
||||
|
||||
for i, b in pairs(current_blocks) do
|
||||
for _, b in pairs(current_blocks) do
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_block(function(minp, maxp, blockseed), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_blocks_nodes) do
|
||||
v.f(b.minp, b.maxp, b.seed)
|
||||
v.f(b.minp, b.maxp, b.blockseed)
|
||||
end
|
||||
current_blocks[i] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
|
@ -393,16 +412,6 @@ mcl_mapgen.minecraft_height_limit = 256
|
|||
|
||||
mcl_mapgen.bedrock_is_rough = normal
|
||||
|
||||
--[[ Realm stacking (h is for height)
|
||||
- Overworld (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Realm Barrier (h=11), to allow escaping the End
|
||||
- End (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Nether (h=128)
|
||||
- Void (h>=1000)
|
||||
]]
|
||||
|
||||
-- Overworld
|
||||
overworld.min = -62
|
||||
if superflat then
|
||||
|
@ -434,15 +443,13 @@ else
|
|||
nether.bedrock_top_min = nether.bedrock_top_max
|
||||
nether.lava_max = nether.min + 2
|
||||
end
|
||||
if mcl_mapgen.name == "flat" then
|
||||
if superflat then
|
||||
nether.flat_floor = nether.bedrock_bottom_max + 4
|
||||
nether.flat_ceiling = nether.bedrock_bottom_max + 52
|
||||
else
|
||||
elseif flat then
|
||||
nether.flat_floor = nether.lava_max + 4
|
||||
nether.flat_ceiling = nether.lava_max + 52
|
||||
end
|
||||
end
|
||||
|
||||
-- The End (surface at ca. Y = -27000)
|
||||
end_.min = -27073 -- Carefully chosen to be at a mapchunk border
|
||||
|
@ -498,5 +505,31 @@ function mcl_mapgen.clamp_to_chunk(x, size)
|
|||
end
|
||||
|
||||
function mcl_mapgen.get_chunk_beginning(x)
|
||||
if tonumber(x) then
|
||||
return x - ((x + central_chunk_min_pos) % CS_NODES)
|
||||
end
|
||||
if x.x then
|
||||
return {
|
||||
x = mcl_mapgen.get_chunk_beginning(x.x),
|
||||
y = mcl_mapgen.get_chunk_beginning(x.y),
|
||||
z = mcl_mapgen.get_chunk_beginning(x.z)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_mapgen.get_chunk_ending(x)
|
||||
if tonumber(x) then
|
||||
return mcl_mapgen.get_chunk_beginning(x) + LAST_NODE_IN_CHUNK
|
||||
end
|
||||
if x.x then
|
||||
return {
|
||||
x = mcl_mapgen.get_chunk_beginning(x.x) + LAST_NODE_IN_CHUNK,
|
||||
y = mcl_mapgen.get_chunk_beginning(x.y) + LAST_NODE_IN_CHUNK,
|
||||
z = mcl_mapgen.get_chunk_beginning(x.z) + LAST_NODE_IN_CHUNK
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
mcl_mapgen.get_block_seed = get_block_seed
|
||||
mcl_mapgen.get_block_seed2 = get_block_seed2
|
||||
mcl_mapgen.get_block_seed3 = get_block_seed3
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# mcl_time
|
||||
## by kay27 for MineClone 5
|
||||
---------------------------
|
||||
This mod counts time when all players sleep or some area is inactive.
|
||||
|
||||
It depends very much on `time_speed` configuration variable, which could be changed 'on the fly' by a chat command.
|
||||
|
||||
If `time_speed` set to 0, this mod logs warnings and returns zeroes.
|
||||
|
||||
### mcl_time.get_seconds_irl()
|
||||
------------------------------
|
||||
Returns: Integer value of realtime (not in-game) seconds since world creation.
|
||||
|
||||
Usually this value grow smoothly. But when you skip the night being in the bed, or leave some area for some time, you may experience value jumps. That's basically the idea of this mod.
|
||||
|
||||
### mcl_time.get_number_of_times(last_time, interval, chance)
|
||||
-------------------------------------------------------------
|
||||
Handy to process AMBs.
|
||||
|
||||
You pass `last_time` - last known value of `seconds_irl`, also ABM `interval` and ABM `chance`.
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times ABM function should be called if the area was active all the time and you didn't skip the night.
|
||||
* Integer value of realtime (not in-game) seconds since world creation.
|
||||
|
||||
### mcl_time.touch(pos)
|
||||
-----------------------
|
||||
This function 'toches' node at position `pos` by writing `_t` meta variable of `seconds_irl`.
|
||||
|
||||
### mcl_time.get_number_of_times_at_pos(pos, interval, chance)
|
||||
--------------------------------------------------------------
|
||||
Much more handy to call from LBM on area load, than `mcl_time.get_number_of_times()`!
|
||||
|
||||
It reads meta variable `_t` from position `pos` and uses it as previous `seconds_irl`, which then pass as first argument into `mcl_time.get_number_of_times()`.
|
||||
After calling this, it also 'touches' the node at `pos` by writing `seconds_irl` into meta variable `_t`.
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times ABM function should be called if the area was active all the time and you didn't skip the night.
|
||||
* Integer value of realtime (not in-game) seconds since world creation.
|
||||
|
||||
*Warning!* This function can return 0. So it's better not to use it for regular ABMs - use `mcl_time.get_number_of_times_at_pos_or_1()` instead.
|
||||
|
||||
### mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance)
|
||||
-------------------------------------------------------------------
|
||||
Much more handy to process ABMs than `mcl_time.get_number_of_times()` and `mcl_time.get_number_of_times_at_pos()`!
|
||||
|
||||
It just calls `mcl_time.get_number_of_times_at_pos()` but doesn't return 0, the minimum number it can return is 1,
|
||||
which is the most suitable for regular ABM processing function.
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times ABM function should be called if the area was active all the time and you didn't skip the night.
|
||||
* Integer value of realtime (not in-game) seconds since world creation.
|
|
@ -0,0 +1,140 @@
|
|||
mcl_time = {}
|
||||
|
||||
local time_update_interval = 2
|
||||
local retry_on_fail_interval = 500
|
||||
local default_time_speed = 72
|
||||
local save_to_storage_interval = 600
|
||||
local meta_name = "_t"
|
||||
|
||||
local current_time_update_interval = time_update_interval
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
local seconds_irl_public = tonumber(storage:get_string("seconds_irl")) or -2
|
||||
local last_save_seconds_irl = seconds_irl_public
|
||||
local next_save_seconds_irl = last_save_seconds_irl + save_to_storage_interval
|
||||
|
||||
local previous_seconds_irl = -2
|
||||
local function get_seconds_irl()
|
||||
local time_speed = tonumber(minetest.settings:get("time_speed") or default_time_speed)
|
||||
if time_speed < 1 then
|
||||
minetest.log("warning", "[mcl_time] time_speed < 1 - please increase to make mcl_time api work (default: " .. default_time_speed .. ")")
|
||||
return 0
|
||||
end
|
||||
local irl_multiplier = 86400 / time_speed
|
||||
local day_count = minetest.get_day_count()
|
||||
local timeofday = minetest.get_timeofday()
|
||||
local seconds_irl
|
||||
if not day_count or not timeofday then
|
||||
seconds_irl = seconds_irl_public
|
||||
else
|
||||
local days_ig = 0.0 + day_count + timeofday
|
||||
seconds_irl = days_ig * irl_multiplier
|
||||
end
|
||||
|
||||
if previous_seconds_irl == seconds_irl then
|
||||
current_time_update_interval = math.min(current_time_update_interval * 2, retry_on_fail_interval)
|
||||
minetest.log("warning", "[mcl_time] Time doesn't change! seconds_irl=" .. tostring(seconds_irl)
|
||||
.. ", day_count = " .. tostring(day_count) .. ", timeofday=" .. tostring(timeofday)
|
||||
.. " - increasing update interval to " .. tostring(current_time_update_interval))
|
||||
else
|
||||
previous_seconds_irl = seconds_irl
|
||||
if current_time_update_interval ~= time_update_interval then
|
||||
current_time_update_interval = time_update_interval
|
||||
minetest.log("action", "[mcl_time] Time is changing again: seconds_irl=" .. tostring(seconds_irl)
|
||||
.. ", day_count = " .. tostring(day_count) .. ", timeofday=" .. tostring(timeofday)
|
||||
.. ", update_interval=" .. tostring(current_time_update_interval))
|
||||
end
|
||||
end
|
||||
|
||||
if last_save_seconds_irl >= next_save_seconds_irl then
|
||||
storage:set_string("seconds_irl", tostring(seconds_irl))
|
||||
next_save_seconds_irl = seconds_irl + save_to_storage_interval
|
||||
end
|
||||
|
||||
return seconds_irl
|
||||
end
|
||||
|
||||
local seconds_irl_public = get_seconds_irl()
|
||||
|
||||
function mcl_time.get_seconds_irl()
|
||||
return seconds_irl_public
|
||||
end
|
||||
|
||||
local function time_runner()
|
||||
seconds_irl_public = get_seconds_irl()
|
||||
minetest.after(current_time_update_interval, time_runner)
|
||||
end
|
||||
|
||||
function mcl_time.get_number_of_times(last_time, interval, chance)
|
||||
if not last_time then return 0 end
|
||||
if seconds_irl_public < 2 then return 0 end
|
||||
if not interval then return 0 end
|
||||
if not chance then return 0 end
|
||||
if interval < 1 then return 0 end
|
||||
if chance < 1 then return 0 end
|
||||
local number_of_intervals = (seconds_irl_public - last_time) / interval
|
||||
if number_of_intervals < 1 then return 0 end
|
||||
local average_chance = (1 + chance) / 2
|
||||
local number_of_times = math.floor(number_of_intervals / average_chance)
|
||||
return number_of_times, seconds_irl_public
|
||||
end
|
||||
|
||||
local get_number_of_times = mcl_time.get_number_of_times
|
||||
|
||||
function mcl_time.touch(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
end
|
||||
|
||||
local touch = mcl_time.touch
|
||||
|
||||
function mcl_time.get_number_of_times_at_pos(pos, interval, chance)
|
||||
if not pos then return 0 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
local number_of_times = (last_time == 0) and 0 or get_number_of_times(last_time, interval, chance)
|
||||
touch(pos)
|
||||
return number_of_times, seconds_irl_public
|
||||
end
|
||||
|
||||
local get_number_of_times_at_pos = mcl_time.get_number_of_times_at_pos
|
||||
|
||||
function mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance)
|
||||
return math.max(get_number_of_times_at_pos(pos, interval, chance), 1), seconds_irl_public
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos(pos)
|
||||
if not pos then return 0 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
local irl_seconds_passed = (last_time == 0) and 0 or (seconds_irl_public - last_time)
|
||||
return irl_seconds_passed
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos_or_1(pos)
|
||||
if not pos then return 1 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
local irl_seconds_passed = (last_time == 0) and 1 or (seconds_irl_public - last_time)
|
||||
return irl_seconds_passed
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos_or_nil(pos)
|
||||
if not pos then return end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
if last_time == 0 then return end
|
||||
local delta_time = seconds_irl_public - last_time
|
||||
if delta_time <= 0 then return end
|
||||
return delta_time
|
||||
end
|
||||
|
||||
time_runner()
|
||||
local day_count = minetest.get_day_count()
|
||||
local timeofday = minetest.get_timeofday()
|
||||
minetest.log("action", "[mcl_time] time runner started, current in-real-life seconds: " .. seconds_irl_public
|
||||
.. ", time_speed: " .. tostring(minetest.settings:get("time_speed"))
|
||||
.. ", day_count: " .. tostring(day_count)
|
||||
.. ", timeofday: " .. tostring(timeofday)
|
||||
.. ", update_interval=" .. tostring(current_time_update_interval)
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_time
|
||||
author = kay27
|
||||
description = This mod counts time when all players sleep or some area is inactive
|
|
@ -2,6 +2,10 @@ local S = minetest.get_translator(minetest.get_current_modname())
|
|||
|
||||
local table = table
|
||||
|
||||
local interval = 35
|
||||
local chance = 11
|
||||
local max_interval = interval * chance
|
||||
|
||||
minetest.register_node("mcl_nether:nether_wart_0", {
|
||||
description = S("Premature Nether Wart (Stage 1)"),
|
||||
_doc_items_longdesc = S("A premature nether wart has just recently been planted on soul sand. Nether wart slowly grows on soul sand in 4 stages (the second and third stages look identical). Although nether wart is home to the Nether, it grows in any dimension."),
|
||||
|
@ -148,18 +152,7 @@ minetest.register_craftitem("mcl_nether:nether_wart_item", {
|
|||
|
||||
local names = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"}
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Nether wart growth",
|
||||
nodenames = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"},
|
||||
neighbors = {"group:soil_nether_wart"},
|
||||
interval = 35,
|
||||
chance = 11,
|
||||
action = function(pos, node)
|
||||
pos.y = pos.y-1
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "soil_nether_wart") == 0 then
|
||||
return
|
||||
end
|
||||
pos.y = pos.y+1
|
||||
local function grow(pos, node)
|
||||
local step = nil
|
||||
for i, name in ipairs(names) do
|
||||
if name == node.name then
|
||||
|
@ -167,16 +160,52 @@ minetest.register_abm({
|
|||
break
|
||||
end
|
||||
end
|
||||
if step == nil then
|
||||
return
|
||||
end
|
||||
if not step then return end
|
||||
local new_node = {name = names[step + 1]}
|
||||
if new_node.name == nil then
|
||||
if not new_node.name then
|
||||
new_node.name = "mcl_nether:nether_wart"
|
||||
end
|
||||
new_node.param = node.param
|
||||
new_node.param2 = node.param2
|
||||
minetest.set_node(pos, new_node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("gametime", tostring(mcl_time:get_seconds_irl()))
|
||||
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Nether wart growth",
|
||||
nodenames = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"},
|
||||
neighbors = {"group:soil_nether_wart"},
|
||||
interval = interval,
|
||||
chance = chance,
|
||||
action = function(pos, node)
|
||||
pos.y = pos.y-1
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "soil_nether_wart") == 0 then
|
||||
return
|
||||
end
|
||||
pos.y = pos.y+1
|
||||
|
||||
for i = 1, mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance) do
|
||||
grow(pos, node)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Nether wart growth update",
|
||||
name = "mcl_nether:growth_warts",
|
||||
nodenames = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
pos.y = pos.y-1
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "soil_nether_wart") == 0 then
|
||||
return
|
||||
end
|
||||
pos.y = pos.y+1
|
||||
for i = 1, mcl_time.get_number_of_times_at_pos(pos, interval, chance) do
|
||||
grow(pos, node)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
local c_dirt_with_grass_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow")
|
||||
local c_top_snow = minetest.get_content_id("mcl_core:snow")
|
||||
local c_snow_block = minetest.get_content_id("mcl_core:snowblock")
|
||||
|
||||
mcl_mapgen.register_on_generated(function(vm_context)
|
||||
local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
local min_y, max_y = minp.y, maxp.y
|
||||
if min_y > mcl_mapgen.overworld.max or max_y < mcl_mapgen.overworld.min then return end
|
||||
|
||||
vm_context.param2_data = vm_context.param2_data or vm:get_param2_data(vm_context.lvm_param2_buffer)
|
||||
vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object("biomemap")
|
||||
local param2_data = vm_context.param2_data
|
||||
local biomemap = vm_context.biomemap
|
||||
local vm, data, area = vm_context.vm, vm_context.data, vm_context.area
|
||||
|
||||
local min_x, min_z = minp.x, minp.z
|
||||
local chunksize = max_y - min_y + 1
|
||||
|
||||
----- Interactive block fixing section -----
|
||||
----- The section to perform basic block overrides of the core mapgen generated world. -----
|
||||
|
||||
-- Snow and sand fixes. This code implements snow consistency
|
||||
-- and fixes floating sand and cut plants.
|
||||
-- A snowy grass block must be below a top snow or snow block at all times.
|
||||
|
||||
-- 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"})
|
||||
|
||||
for n=1, #nodes do
|
||||
local pos = nodes[n]
|
||||
local x, y, z = pos.x, pos.y, pos.z
|
||||
local p_pos = area:index(x, y, z)
|
||||
local p_pos_above = area:index(x, y + 1, z)
|
||||
local biomemap_offset = (z - min_z) * chunksize + x - min_x + 1
|
||||
local biome_id = biomemap[biomemap_offset]
|
||||
local biome_name = minetest.get_biome_name(biome_id)
|
||||
if biome_name then
|
||||
local biome = minetest.registered_biomes[biome_name]
|
||||
if biome and biome._mcl_biome_type then
|
||||
param2_data[p_pos] = biome._mcl_palette_index
|
||||
vm_context.write_param2 = 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
|
||||
data[p_pos] = c_dirt_with_grass
|
||||
vm_context.write = true
|
||||
end
|
||||
end
|
||||
end, 999999999)
|
|
@ -56,19 +56,14 @@ local mg_name = mcl_mapgen.name
|
|||
local superflat = mcl_mapgen.superflat
|
||||
local v6 = mcl_mapgen.v6
|
||||
local singlenode = mcl_mapgen.singlenode
|
||||
local flat = mcl_mapgen.flat
|
||||
|
||||
-- Content IDs
|
||||
local c_bedrock = minetest.get_content_id("mcl_core:bedrock")
|
||||
local c_obsidian = minetest.get_content_id("mcl_core:obsidian")
|
||||
local c_stone = minetest.get_content_id("mcl_core:stone")
|
||||
local c_dirt = minetest.get_content_id("mcl_core:dirt")
|
||||
local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass")
|
||||
local c_dirt_with_grass_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow")
|
||||
local c_sand = minetest.get_content_id("mcl_core:sand")
|
||||
--local c_sandstone = minetest.get_content_id("mcl_core:sandstone")
|
||||
local c_void = minetest.get_content_id("mcl_core:void")
|
||||
local c_lava = minetest.get_content_id("mcl_core:lava_source")
|
||||
local c_water = minetest.get_content_id("mcl_core:water_source")
|
||||
|
||||
local c_nether = nil
|
||||
if minetest.get_modpath("mcl_nether") then
|
||||
|
@ -79,12 +74,7 @@ if minetest.get_modpath("mcl_nether") then
|
|||
}
|
||||
end
|
||||
|
||||
--local c_end_stone = minetest.get_content_id("mcl_end:end_stone")
|
||||
local c_realm_barrier = minetest.get_content_id("mcl_core:realm_barrier")
|
||||
local c_top_snow = minetest.get_content_id("mcl_core:snow")
|
||||
local c_snow_block = minetest.get_content_id("mcl_core:snowblock")
|
||||
local c_clay = minetest.get_content_id("mcl_core:clay")
|
||||
--local c_jungletree = minetest.get_content_id("mcl_core:jungletree")
|
||||
local c_air = minetest.CONTENT_AIR
|
||||
|
||||
--
|
||||
|
@ -1143,166 +1133,6 @@ if string.len(mg_flags_str) > 0 then
|
|||
end
|
||||
minetest.set_mapgen_setting("mg_flags", mg_flags_str, true)
|
||||
|
||||
-- Takes an index of a biomemap table (from minetest.get_mapgen_object),
|
||||
-- minp and maxp (from an on_generated callback) and returns the real world coordinates
|
||||
-- as X, Z.
|
||||
-- Inverse function of xz_to_biomemap
|
||||
--[[local function biomemap_to_xz(index, minp, maxp)
|
||||
local xwidth = maxp.x - minp.x + 1
|
||||
local zwidth = maxp.z - minp.z + 1
|
||||
local x = ((index-1) % xwidth) + minp.x
|
||||
local z = ((index-1) / zwidth) + minp.z
|
||||
return x, z
|
||||
end]]
|
||||
|
||||
local dragon_spawn_pos = false
|
||||
local dragon_spawned, portal_generated = false, false
|
||||
|
||||
local function spawn_ender_dragon()
|
||||
local obj = minetest.add_entity(dragon_spawn_pos, "mobs_mc:enderdragon")
|
||||
if not obj then return false end
|
||||
local dragon_entity = obj:get_luaentity()
|
||||
dragon_entity._initial = true
|
||||
dragon_entity._portal_pos = pos
|
||||
return obj
|
||||
end
|
||||
|
||||
local function try_to_spawn_ender_dragon()
|
||||
if spawn_ender_dragon() then
|
||||
dragon_spawned = true
|
||||
return
|
||||
end
|
||||
minetest.after(2, try_to_spawn_ender_dragon)
|
||||
minetest.log("warning", "[mcl_mapgen_core] WARNING! Ender dragon doesn't want to spawn at "..minetest.pos_to_string(dragon_spawn_pos))
|
||||
end
|
||||
|
||||
if portal_generated and not dragon_spawned then
|
||||
minetest.after(10, try_to_spawn_ender_dragon)
|
||||
end
|
||||
|
||||
function mcl_mapgen_core.generate_end_exit_portal(pos)
|
||||
if dragon_spawn_pos then return false end
|
||||
dragon_spawn_pos = vector.add(pos, vector.new(3, 11, 3))
|
||||
mcl_structures.call_struct(pos, "end_exit_portal", nil, nil, function()
|
||||
minetest.after(2, function()
|
||||
minetest.emerge_area(vector.subtract(dragon_spawn_pos, {x = 64, y = 12, z = 5}), vector.add(dragon_spawn_pos, {x = 3, y = 3, z = 5}), function(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining > 0 then return end
|
||||
minetest.after(2, try_to_spawn_ender_dragon)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
portal_generated = true
|
||||
end
|
||||
|
||||
-- Generate mushrooms in caves manually.
|
||||
-- Minetest's API does not support decorations in caves yet. :-(
|
||||
local function generate_underground_mushrooms(minp, maxp, seed)
|
||||
if not mcl_mushrooms then return end
|
||||
|
||||
local pr_shroom = PseudoRandom(seed-24359)
|
||||
-- Generate rare underground mushrooms
|
||||
-- TODO: Make them appear in groups, use Perlin noise
|
||||
local min, max = mcl_mapgen.overworld.lava_max + 4, 0
|
||||
if minp.y > max or maxp.y < min then
|
||||
return
|
||||
end
|
||||
|
||||
local bpos
|
||||
local stone = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_core:stone", "mcl_core:dirt", "mcl_core:mycelium", "mcl_core:podzol", "mcl_core:andesite", "mcl_core:diorite", "mcl_core:granite", "mcl_core:stone_with_coal", "mcl_core:stone_with_iron", "mcl_core:stone_with_gold"})
|
||||
|
||||
for n = 1, #stone do
|
||||
bpos = {x = stone[n].x, y = stone[n].y + 1, z = stone[n].z }
|
||||
|
||||
local l = minetest.get_node_light(bpos, 0.5)
|
||||
if bpos.y >= min and bpos.y <= max and l and l <= 12 and pr_shroom:next(1,1000) < 4 then
|
||||
if pr_shroom:next(1,2) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
|
||||
else
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local nether_wart_chance
|
||||
if v6 then
|
||||
nether_wart_chance = 85
|
||||
else
|
||||
nether_wart_chance = 170
|
||||
end
|
||||
-- Generate Nether decorations manually: Eternal fire, mushrooms, nether wart
|
||||
-- Minetest's API does not support decorations in caves yet. :-(
|
||||
local function generate_nether_decorations(minp, maxp, seed)
|
||||
if c_nether == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local pr_nether = PseudoRandom(seed+667)
|
||||
|
||||
if minp.y > mcl_mapgen.nether.max or maxp.y < mcl_mapgen.nether.min then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.log("action", "[mcl_mapgen_core] Nether decorations " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp))
|
||||
|
||||
-- TODO: Generate everything based on Perlin noise instead of PseudoRandom
|
||||
|
||||
local bpos
|
||||
local rack = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:netherrack"})
|
||||
local magma = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:magma"})
|
||||
local ssand = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:soul_sand"})
|
||||
|
||||
-- Helper function to spawn “fake” decoration
|
||||
local function special_deco(nodes, spawn_func)
|
||||
for n = 1, #nodes do
|
||||
bpos = {x = nodes[n].x, y = nodes[n].y + 1, z = nodes[n].z }
|
||||
|
||||
spawn_func(bpos)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Eternal fire on netherrack
|
||||
special_deco(rack, function(bpos)
|
||||
-- Eternal fire on netherrack
|
||||
if pr_nether:next(1,100) <= 3 then
|
||||
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
|
||||
end
|
||||
end)
|
||||
|
||||
-- Eternal fire on magma cubes
|
||||
special_deco(magma, function(bpos)
|
||||
if pr_nether:next(1,150) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
|
||||
end
|
||||
end)
|
||||
|
||||
-- Mushrooms on netherrack
|
||||
-- Note: Spawned *after* the fire because of light level checks
|
||||
if mcl_mushrooms then
|
||||
special_deco(rack, function(bpos)
|
||||
local l = minetest.get_node_light(bpos, 0.5)
|
||||
if bpos.y > mcl_mapgen.nether.lava_max + 6 and l and l <= 12 and pr_nether:next(1,1000) <= 4 then
|
||||
-- TODO: Make mushrooms appear in groups, use Perlin noise
|
||||
if pr_nether:next(1,2) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
|
||||
else
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Nether wart on soul sand
|
||||
-- TODO: Spawn in Nether fortresses
|
||||
special_deco(ssand, function(bpos)
|
||||
if pr_nether:next(1, nether_wart_chance) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_nether:nether_wart"})
|
||||
end
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
-- Generate basic layer-based nodes: void, bedrock, realm barrier, lava seas, etc.
|
||||
-- Also perform some basic node replacements.
|
||||
|
||||
|
@ -1353,267 +1183,96 @@ end
|
|||
-- 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)
|
||||
local function set_layers(vm_context, pr, min, max, content_id, check)
|
||||
local minp, maxp, data, area = vm_context.minp, vm_context.maxp, vm_context.data, vm_context.area
|
||||
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)
|
||||
local p_pos = vm_context.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
|
||||
vm_context.write = true
|
||||
elseif check == data[p_pos] then
|
||||
data[p_pos] = content_id
|
||||
lvm_used = true
|
||||
vm_context.write = true
|
||||
end
|
||||
else
|
||||
data[p_pos] = content_id
|
||||
lvm_used = true
|
||||
vm_context.data[p_pos] = content_id
|
||||
vm_context.write = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return lvm_used
|
||||
end
|
||||
|
||||
-- Below the bedrock, generate air/void
|
||||
local function basic_safe(vm_context)
|
||||
local vm, data, emin, emax, area, minp, maxp, chunkseed, blockseed = vm_context.vm, vm_context.data, vm_context.emin, vm_context.emax, vm_context.area, vm_context.minp, vm_context.maxp, vm_context.chunkseed, vm_context.blockseed
|
||||
---- Generate layers of air, void, etc
|
||||
local air_layers = {
|
||||
{mcl_mapgen.nether.max + 1, mcl_mapgen.nether.max + 128} -- on Nether Roof
|
||||
}
|
||||
if flat then
|
||||
air_layers[#air_layers + 1] = {mcl_mapgen.nether.flat_floor, mcl_mapgen.nether.flat_ceiling} -- Flat Nether
|
||||
end
|
||||
|
||||
-- Realm barrier between the Overworld void and the End
|
||||
local barrier_min = mcl_mapgen.realm_barrier_overworld_end_min
|
||||
local barrier_max = mcl_mapgen.realm_barrier_overworld_end_max
|
||||
|
||||
local void_layers = {
|
||||
{mcl_mapgen.EDGE_MIN , mcl_mapgen.nether.min - 1 }, -- below Nether
|
||||
{mcl_mapgen.nether.max + 129, mcl_mapgen.end_.min - 1 }, -- below End (above Nether)
|
||||
{mcl_mapgen.end_.max + 1 , barrier_min - 1 }, -- below Realm Barrier, above End
|
||||
{barrier_max + 1 , mcl_mapgen.overworld.min - 1}, -- below Overworld, above Realm Barrier
|
||||
}
|
||||
|
||||
local bedrock_layers = {}
|
||||
if not singlenode then
|
||||
bedrock_layers = {
|
||||
{mcl_mapgen.overworld.bedrock_min , mcl_mapgen.overworld.bedrock_max },
|
||||
{mcl_mapgen.nether.bedrock_bottom_min, mcl_mapgen.nether.bedrock_bottom_max},
|
||||
{mcl_mapgen.nether.bedrock_top_min , mcl_mapgen.nether.bedrock_top_max },
|
||||
}
|
||||
end
|
||||
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local vm, data, area, minp, maxp, chunkseed, blockseed = vm_context.vm, vm_context.data, vm_context.area, vm_context.minp, vm_context.maxp, vm_context.chunkseed, vm_context.blockseed
|
||||
vm_context.param2_data = vm_context.param2_data or vm:get_param2_data(vm_context.lvm_param2_buffer)
|
||||
local param2_data = vm_context.param2_data
|
||||
|
||||
local lvm_used = false
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
-- The Void below the Nether:
|
||||
lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.EDGE_MIN , mcl_mapgen.nether.min -1, minp, maxp, lvm_used, pr)
|
||||
|
||||
-- [[ THE NETHER: mcl_mapgen.nether.min mcl_mapgen.nether.max ]]
|
||||
|
||||
-- The Air on the Nether roof, https://git.minetest.land/MineClone2/MineClone2/issues/1186
|
||||
lvm_used = set_layers(data, area, c_air , nil, mcl_mapgen.nether.max +1, mcl_mapgen.nether.max + 128 , minp, maxp, lvm_used, pr)
|
||||
-- The Void above the Nether below the End:
|
||||
lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.nether.max + 128 +1, mcl_mapgen.end_.min -1, minp, maxp, lvm_used, pr)
|
||||
|
||||
-- [[ THE END: mcl_mapgen.end_.min mcl_mapgen.end_.max ]]
|
||||
|
||||
-- The Void above the End below the Realm barrier:
|
||||
lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.end_.max +1, mcl_mapgen.realm_barrier_overworld_end_min-1, minp, maxp, lvm_used, pr)
|
||||
-- Realm barrier between the Overworld void and the End
|
||||
lvm_used = set_layers(data, area, c_realm_barrier, nil, mcl_mapgen.realm_barrier_overworld_end_min , mcl_mapgen.realm_barrier_overworld_end_max , minp, maxp, lvm_used, pr)
|
||||
-- The Void above Realm barrier below the Overworld:
|
||||
lvm_used = set_layers(data, area, c_void , nil, mcl_mapgen.realm_barrier_overworld_end_max+1, mcl_mapgen.overworld.min -1, minp, maxp, lvm_used, pr)
|
||||
|
||||
|
||||
if not singlenode then
|
||||
-- Bedrock
|
||||
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_mapgen.overworld.bedrock_min, mcl_mapgen.overworld.bedrock_max, minp, maxp, lvm_used, pr)
|
||||
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_mapgen.nether.bedrock_bottom_min, mcl_mapgen.nether.bedrock_bottom_max, minp, maxp, lvm_used, pr)
|
||||
lvm_used = set_layers(data, area, c_bedrock, bedrock_check, mcl_mapgen.nether.bedrock_top_min, mcl_mapgen.nether.bedrock_top_max, minp, maxp, lvm_used, pr)
|
||||
|
||||
-- Flat Nether
|
||||
if mg_name == "flat" then
|
||||
lvm_used = set_layers(data, area, c_air, nil, mcl_mapgen.nether.flat_floor, mcl_mapgen.nether.flat_ceiling, minp, maxp, lvm_used, pr)
|
||||
for _, layer in pairs(void_layers) do
|
||||
set_layers(vm_context, pr, layer[1], layer[2], c_void)
|
||||
end
|
||||
|
||||
for _, layer in pairs(air_layers) do
|
||||
set_layers(vm_context, pr, layer[1], layer[2], c_air)
|
||||
end
|
||||
set_layers(vm_context, pr, barrier_min, barrier_max, c_realm_barrier)
|
||||
for _, layer in pairs(bedrock_layers) do
|
||||
set_layers(vm_context, pr, layer[1], layer[2], c_bedrock, bedrock_check)
|
||||
end
|
||||
if not singlenode then
|
||||
-- Big lava seas by replacing air below a certain height
|
||||
if mcl_mapgen.lava then
|
||||
lvm_used = set_layers(data, area, c_lava, c_air, mcl_mapgen.overworld.min, mcl_mapgen.overworld.lava_max, minp, maxp, lvm_used, pr)
|
||||
set_layers(vm_context, pr, mcl_mapgen.overworld.min, mcl_mapgen.overworld.lava_max, c_lava, c_air)
|
||||
if c_nether then
|
||||
lvm_used = set_layers(data, area, c_nether.lava, c_air, mcl_mapgen.nether.min, mcl_mapgen.nether.lava_max, minp, maxp, lvm_used, pr)
|
||||
end
|
||||
end
|
||||
|
||||
vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object("biomemap")
|
||||
local biomemap = vm_context.biomemap
|
||||
|
||||
----- Interactive block fixing section -----
|
||||
----- The section to perform basic block overrides of the core mapgen generated world. -----
|
||||
|
||||
-- Snow and sand fixes. This code implements snow consistency
|
||||
-- and fixes floating sand and cut plants.
|
||||
-- A snowy grass block must be below a top snow or snow block at all times.
|
||||
if minp.y <= mcl_mapgen.overworld.max and maxp.y >= mcl_mapgen.overworld.min then
|
||||
-- v6 mapgen:
|
||||
if v6 then
|
||||
|
||||
--[[ Remove broken double plants caused by v6 weirdness.
|
||||
v6 might break the bottom part of double plants because of how it works.
|
||||
There are 3 possibilities:
|
||||
1) Jungle: Top part is placed on top of a jungle tree or fern (=v6 jungle grass).
|
||||
This is because the schematic might be placed even if some nodes of it
|
||||
could not be placed because the destination was already occupied.
|
||||
TODO: A better fix for this would be if schematics could abort placement
|
||||
altogether if ANY of their nodes could not be placed.
|
||||
2) Cavegen: Removes the bottom part, the upper part floats
|
||||
3) Mudflow: Same as 2) ]]
|
||||
local plants = minetest.find_nodes_in_area(minp, maxp, "group:double_plant")
|
||||
for n = 1, #plants do
|
||||
local node = vm:get_node_at(plants[n])
|
||||
local is_top = minetest.get_item_group(node.name, "double_plant") == 2
|
||||
if is_top then
|
||||
local p_pos = area:index(plants[n].x, plants[n].y-1, plants[n].z)
|
||||
if p_pos then
|
||||
node = vm:get_node_at({x=plants[n].x, y=plants[n].y-1, z=plants[n].z})
|
||||
local is_bottom = minetest.get_item_group(node.name, "double_plant") == 1
|
||||
if not is_bottom then
|
||||
p_pos = area:index(plants[n].x, plants[n].y, plants[n].z)
|
||||
data[p_pos] = c_air
|
||||
lvm_used = true
|
||||
set_layers(vm_context, pr, mcl_mapgen.nether.min, mcl_mapgen.nether.lava_max, c_nether.lava, c_air)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Non-v6 mapgens:
|
||||
else
|
||||
-- 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 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 and biome._mcl_biome_type then
|
||||
param2_data[p_pos] = biome._mcl_palette_index
|
||||
vm_context.write_param2 = 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
|
||||
data[p_pos] = c_dirt_with_grass
|
||||
lvm_used = true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Nether block fixes:
|
||||
-- * Replace water with Nether lava.
|
||||
-- * Replace stone, sand dirt in v6 so the Nether works in v6.
|
||||
elseif minp.y <= mcl_mapgen.nether.max and maxp.y >= mcl_mapgen.nether.min then
|
||||
-- elseif emin.y <= mcl_mapgen.nether.max and emax.y >= mcl_mapgen.nether.min then
|
||||
if c_nether then
|
||||
if v6 then
|
||||
-- local nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
|
||||
for n=1, #nodes do
|
||||
local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z)
|
||||
if data[p_pos] == c_water then
|
||||
data[p_pos] = c_nether.lava
|
||||
lvm_used = true
|
||||
elseif data[p_pos] == c_stone then
|
||||
data[p_pos] = c_netherrack
|
||||
lvm_used = true
|
||||
elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then
|
||||
data[p_pos] = c_soul_sand
|
||||
lvm_used = true
|
||||
end
|
||||
end
|
||||
else
|
||||
-- local nodes = minetest.find_nodes_in_area(emin, emax, {"group:water"})
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"group:water"})
|
||||
for _, n in pairs(nodes) do
|
||||
data[area:index(n.x, n.y, n.z)] = c_nether.lava
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- End block fixes:
|
||||
-- * Replace water with end stone or air (depending on height).
|
||||
-- * Remove stone, sand, dirt in v6 so our End map generator works in v6.
|
||||
-- * Generate spawn platform (End portal destination)
|
||||
elseif minp.y <= mcl_mapgen.end_.max and maxp.y >= mcl_mapgen.end_.min then
|
||||
local nodes
|
||||
if v6 then
|
||||
nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
|
||||
-- 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(minp, maxp, {"mcl_core:water_source"})
|
||||
-- nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source"})
|
||||
end
|
||||
if #nodes > 0 then
|
||||
lvm_used = true
|
||||
for _,n in pairs(nodes) do
|
||||
data[area:index(n.x, n.y, n.z)] = c_air
|
||||
end
|
||||
end
|
||||
|
||||
-- Obsidian spawn platform
|
||||
if minp.y <= mcl_mapgen.end_.platform_pos.y and maxp.y >= mcl_mapgen.end_.platform_pos.y and
|
||||
minp.x <= mcl_mapgen.end_.platform_pos.x and maxp.x >= mcl_mapgen.end_.platform_pos.z and
|
||||
minp.z <= mcl_mapgen.end_.platform_pos.z and maxp.z >= mcl_mapgen.end_.platform_pos.z then
|
||||
|
||||
--local pos1 = {x = math.max(minp.x, mcl_mapgen.end_.platform_pos.x-2), y = math.max(minp.y, mcl_mapgen.end_.platform_pos.y), z = math.max(minp.z, mcl_mapgen.end_.platform_pos.z-2)}
|
||||
--local pos2 = {x = math.min(maxp.x, mcl_mapgen.end_.platform_pos.x+2), y = math.min(maxp.y, mcl_mapgen.end_.platform_pos.y+2), z = math.min(maxp.z, mcl_mapgen.end_.platform_pos.z+2)}
|
||||
|
||||
for x=math.max(minp.x, mcl_mapgen.end_.platform_pos.x-2), math.min(maxp.x, mcl_mapgen.end_.platform_pos.x+2) do
|
||||
for z=math.max(minp.z, mcl_mapgen.end_.platform_pos.z-2), math.min(maxp.z, mcl_mapgen.end_.platform_pos.z+2) do
|
||||
for y=math.max(minp.y, mcl_mapgen.end_.platform_pos.y), math.min(maxp.y, mcl_mapgen.end_.platform_pos.y+2) do
|
||||
local p_pos = area:index(x, y, z)
|
||||
if y == mcl_mapgen.end_.platform_pos.y then
|
||||
data[p_pos] = c_obsidian
|
||||
else
|
||||
data[p_pos] = c_air
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
lvm_used = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if not singlenode then
|
||||
-- Generate special decorations
|
||||
generate_underground_mushrooms(minp, maxp, blockseed)
|
||||
generate_nether_decorations(minp, maxp, blockseed)
|
||||
end
|
||||
|
||||
vm_context.write = vm_context.write or lvm_used
|
||||
end
|
||||
|
||||
mcl_mapgen.register_mapgen_block_lvm(basic_safe, 1)
|
||||
end, 1)
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
dofile(modpath .. "/clay.lua")
|
||||
dofile(modpath .. "/tree_decoration.lua")
|
||||
|
||||
-- Nether Roof Light:
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local minp = vm_context.minp
|
||||
local miny = minp.y
|
||||
if miny > mcl_mapgen.nether.max+127 then return end
|
||||
local maxp = vm_context.maxp
|
||||
local maxy = maxp.y
|
||||
if maxy <= mcl_mapgen.nether.max then return end
|
||||
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.nether.max + 1), z = minp.z}
|
||||
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.nether.max + 127), z = maxp.z}
|
||||
vm_context.vm:set_lighting({day=15, night=15}, p1, p2)
|
||||
vm_context.write = true
|
||||
end, 999999999)
|
||||
|
||||
-- End Light:
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local minp = vm_context.minp
|
||||
local miny = minp.y
|
||||
if miny > mcl_mapgen.end_.max then return end
|
||||
local maxp = vm_context.maxp
|
||||
local maxy = maxp.y
|
||||
if maxy <= mcl_mapgen.end_.min then return end
|
||||
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.end_.min), z = minp.z}
|
||||
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.end_.max), z = maxp.z}
|
||||
vm_context.vm:set_lighting({day=15, night=15}, p1, p2)
|
||||
vm_context.write = true
|
||||
end, 9999999999)
|
||||
dofile(modpath .. "/nether_wart.lua")
|
||||
dofile(modpath .. "/light.lua")
|
||||
if v6 then
|
||||
dofile(modpath .. "/v6.lua")
|
||||
elseif not singlenode then
|
||||
dofile(modpath .. "/biomes.lua")
|
||||
end
|
||||
if not singlenode and c_nether then
|
||||
dofile(modpath .. "/nether.lua")
|
||||
end
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
-- Nether Light:
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local minp = vm_context.minp
|
||||
local miny = minp.y
|
||||
if miny > mcl_mapgen.nether.max then return end
|
||||
local maxp = vm_context.maxp
|
||||
local maxy = maxp.y
|
||||
if maxy < mcl_mapgen.nether.min then return end
|
||||
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.nether.min), z = minp.z}
|
||||
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.nether.max), z = maxp.z}
|
||||
vm_context.vm:set_lighting({day = 3, night = 4}, p1, p2)
|
||||
vm_context.write = true
|
||||
end, 999999999)
|
||||
|
||||
-- Nether Roof Light:
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local minp = vm_context.minp
|
||||
local miny = minp.y
|
||||
if miny > mcl_mapgen.nether.max+127 then return end
|
||||
local maxp = vm_context.maxp
|
||||
local maxy = maxp.y
|
||||
if maxy <= mcl_mapgen.nether.max then return end
|
||||
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.nether.max + 1), z = minp.z}
|
||||
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.nether.max + 127), z = maxp.z}
|
||||
vm_context.vm:set_lighting({day = 15, night = 15}, p1, p2)
|
||||
vm_context.write = true
|
||||
end, 999999999)
|
||||
|
||||
-- End Light:
|
||||
mcl_mapgen.register_mapgen_block_lvm(function(vm_context)
|
||||
local minp = vm_context.minp
|
||||
local miny = minp.y
|
||||
if miny > mcl_mapgen.end_.max then return end
|
||||
local maxp = vm_context.maxp
|
||||
local maxy = maxp.y
|
||||
if maxy <= mcl_mapgen.end_.min then return end
|
||||
local p1 = {x = minp.x, y = math.max(miny, mcl_mapgen.end_.min), z = minp.z}
|
||||
local p2 = {x = maxp.x, y = math.min(maxy, mcl_mapgen.end_.max), z = maxp.z}
|
||||
vm_context.vm:set_lighting({day=15, night=15}, p1, p2)
|
||||
vm_context.write = true
|
||||
end, 9999999999)
|
|
@ -0,0 +1,131 @@
|
|||
local v6 = mcl_mapgen.v6
|
||||
|
||||
local mcl_mushrooms = minetest.get_modpath("mcl_mushrooms")
|
||||
|
||||
local c_water = minetest.get_content_id("mcl_core:water_source")
|
||||
local c_stone = minetest.get_content_id("mcl_core:stone")
|
||||
local c_sand = minetest.get_content_id("mcl_core:sand")
|
||||
|
||||
local c_soul_sand = minetest.get_content_id("mcl_nether:soul_sand")
|
||||
local c_netherrack = minetest.get_content_id("mcl_nether:netherrack")
|
||||
local c_nether_lava = minetest.get_content_id("mcl_nether:nether_lava_source")
|
||||
|
||||
-- Generate mushrooms in caves manually.
|
||||
-- Minetest's API does not support decorations in caves yet. :-(
|
||||
local function generate_underground_mushrooms(minp, maxp, seed)
|
||||
if not mcl_mushrooms then return end
|
||||
|
||||
local pr_shroom = PseudoRandom(seed-24359)
|
||||
-- Generate rare underground mushrooms
|
||||
-- TODO: Make them appear in groups, use Perlin noise
|
||||
local min, max = mcl_mapgen.overworld.lava_max + 4, 0
|
||||
if minp.y > max or maxp.y < min then
|
||||
return
|
||||
end
|
||||
|
||||
local bpos
|
||||
local stone = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_core:stone", "mcl_core:dirt", "mcl_core:mycelium", "mcl_core:podzol", "mcl_core:andesite", "mcl_core:diorite", "mcl_core:granite", "mcl_core:stone_with_coal", "mcl_core:stone_with_iron", "mcl_core:stone_with_gold"})
|
||||
|
||||
for n = 1, #stone do
|
||||
bpos = {x = stone[n].x, y = stone[n].y + 1, z = stone[n].z }
|
||||
|
||||
local l = minetest.get_node_light(bpos, 0.5)
|
||||
if bpos.y >= min and bpos.y <= max and l and l <= 12 and pr_shroom:next(1,1000) < 4 then
|
||||
if pr_shroom:next(1,2) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
|
||||
else
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Generate Nether decorations manually: Eternal fire, mushrooms
|
||||
-- Minetest's API does not support decorations in caves yet. :-(
|
||||
local function generate_nether_decorations(minp, maxp, seed)
|
||||
local pr_nether = PseudoRandom(seed+667)
|
||||
|
||||
if minp.y > mcl_mapgen.nether.max or maxp.y < mcl_mapgen.nether.min then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.log("action", "[mcl_mapgen_core] Nether decorations " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp))
|
||||
|
||||
-- TODO: Generate everything based on Perlin noise instead of PseudoRandom
|
||||
|
||||
local bpos
|
||||
local rack = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:netherrack"})
|
||||
local magma = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:magma"})
|
||||
local ssand = minetest.find_nodes_in_area_under_air(minp, maxp, {"mcl_nether:soul_sand"})
|
||||
|
||||
-- Helper function to spawn “fake” decoration
|
||||
local function special_deco(nodes, spawn_func)
|
||||
for n = 1, #nodes do
|
||||
bpos = {x = nodes[n].x, y = nodes[n].y + 1, z = nodes[n].z }
|
||||
|
||||
spawn_func(bpos)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Eternal fire on netherrack
|
||||
special_deco(rack, function(bpos)
|
||||
-- Eternal fire on netherrack
|
||||
if pr_nether:next(1,100) <= 3 then
|
||||
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
|
||||
end
|
||||
end)
|
||||
|
||||
-- Eternal fire on magma cubes
|
||||
special_deco(magma, function(bpos)
|
||||
if pr_nether:next(1,150) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_fire:eternal_fire"})
|
||||
end
|
||||
end)
|
||||
|
||||
-- Mushrooms on netherrack
|
||||
-- Note: Spawned *after* the fire because of light level checks
|
||||
if mcl_mushrooms then
|
||||
special_deco(rack, function(bpos)
|
||||
local l = minetest.get_node_light(bpos, 0.5)
|
||||
if bpos.y > mcl_mapgen.nether.lava_max + 6 and l and l <= 12 and pr_nether:next(1,1000) <= 4 then
|
||||
-- TODO: Make mushrooms appear in groups, use Perlin noise
|
||||
if pr_nether:next(1,2) == 1 then
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_brown"})
|
||||
else
|
||||
minetest.set_node(bpos, {name = "mcl_mushrooms:mushroom_red"})
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context)
|
||||
local min_y, max_y = minp.y, maxp.y
|
||||
|
||||
-- Nether block fixes:
|
||||
-- * Replace water with Nether lava.
|
||||
-- * Replace stone, sand dirt in v6 so the Nether works in v6.
|
||||
if min_y > mcl_mapgen.nether.max or max_y < mcl_mapgen.nether.min then return end
|
||||
if v6 then
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
|
||||
if #nodes < 1 then return end
|
||||
vm_context.write = true
|
||||
local data = vm_context.data
|
||||
local area = vm_context.area
|
||||
for n = 1, #nodes do
|
||||
local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z)
|
||||
if data[p_pos] == c_water then
|
||||
data[p_pos] = c_nether_lava
|
||||
elseif data[p_pos] == c_stone then
|
||||
data[p_pos] = c_netherrack
|
||||
elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then
|
||||
data[p_pos] = c_soul_sand
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
||||
generate_underground_mushrooms(minp, maxp, seed)
|
||||
generate_nether_decorations(minp, maxp, seed)
|
||||
end, 1)
|
|
@ -0,0 +1,57 @@
|
|||
local nether_wart_chance
|
||||
if mcl_mapgen.v6 then
|
||||
nether_wart_chance = 85
|
||||
else
|
||||
nether_wart_chance = 170
|
||||
end
|
||||
|
||||
local y_min = mcl_mapgen.nether.min
|
||||
local y_max = mcl_mapgen.nether.max
|
||||
local place_on = {"group:soil_nether_wart"}
|
||||
|
||||
local block_size = mcl_mapgen.BS
|
||||
local decrease_search_area = math.min(2, math.floor(block_size/2))
|
||||
local search_area_size = math.max(block_size - 2 * decrease_search_area, math.max(1, math.ceil(nether_wart_chance^(1/3))))
|
||||
nether_wart_chance = math.floor(nether_wart_chance * (search_area_size^3) / (block_size^3))
|
||||
local nether_wart_chance_threshold = nether_wart_chance
|
||||
local minetest_swap_node = minetest.swap_node
|
||||
|
||||
local wart_perlin
|
||||
local noise_params = {
|
||||
offset = 0.4,
|
||||
scale = 0.4,
|
||||
spread = {x = block_size, y = block_size, z = block_size},
|
||||
seed = 238742,
|
||||
octaves = 1,
|
||||
persist = 0.5,
|
||||
}
|
||||
|
||||
minetest.log("action", "Nether Wart block_size=" .. block_size .. ", search_area_size=" .. search_area_size .. ", per-area nether_wart_chance=" .. nether_wart_chance)
|
||||
|
||||
local minetest_find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
|
||||
local minetest_get_perlin = minetest.get_perlin
|
||||
|
||||
mcl_mapgen.register_mapgen_block(function(minp, maxp, seed)
|
||||
local minp = minp
|
||||
local y1 = minp.y
|
||||
if y1 > y_max then return end
|
||||
|
||||
local maxp = maxp
|
||||
local y2 = maxp.y
|
||||
if y2 < y_min then return end
|
||||
|
||||
local p1 = {x = minp.x + decrease_search_area, y = y1 + decrease_search_area, z = minp.z + decrease_search_area}
|
||||
local p2 = {x = maxp.x - decrease_search_area, y = y2 - decrease_search_area, z = maxp.z - decrease_search_area}
|
||||
|
||||
pos_list = minetest_find_nodes_in_area_under_air(p1, p2, place_on)
|
||||
local pr = PseudoRandom(seed)
|
||||
wart_perlin = wart_perlin or minetest_get_perlin(noise_params)
|
||||
|
||||
for i = 1, #pos_list do
|
||||
local pos = pos_list[i]
|
||||
if pr:next(1, nether_wart_chance) + wart_perlin:get_3d(pos) >= nether_wart_chance_threshold then
|
||||
pos.y = pos.y + 1
|
||||
minetest.swap_node(pos, {name = "mcl_nether:nether_wart"})
|
||||
end
|
||||
end
|
||||
end, 999999999)
|
|
@ -0,0 +1,49 @@
|
|||
local c_air = minetest.CONTENT_AIR
|
||||
|
||||
mcl_mapgen.register_on_generated(function(vm_context)
|
||||
local minp, maxp = vm_context.minp, vm_context.maxp
|
||||
|
||||
if minp.y <= mcl_mapgen.end_.max and maxp.y >= mcl_mapgen.end_.min then
|
||||
local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"})
|
||||
if #nodes > 0 then
|
||||
for _, n in pairs(nodes) do
|
||||
data[area:index(n.x, n.y, n.z)] = c_air
|
||||
end
|
||||
end
|
||||
vm_context.write = true
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if minp.y > mcl_mapgen.overworld.max or maxp.y < mcl_mapgen.overworld.min then return end
|
||||
local vm, data, area = vm_context.vm, vm_context.data, vm_context.area
|
||||
|
||||
--[[ Remove broken double plants caused by v6 weirdness.
|
||||
v6 might break the bottom part of double plants because of how it works.
|
||||
There are 3 possibilities:
|
||||
1) Jungle: Top part is placed on top of a jungle tree or fern (=v6 jungle grass).
|
||||
This is because the schematic might be placed even if some nodes of it
|
||||
could not be placed because the destination was already occupied.
|
||||
TODO: A better fix for this would be if schematics could abort placement
|
||||
altogether if ANY of their nodes could not be placed.
|
||||
2) Cavegen: Removes the bottom part, the upper part floats
|
||||
3) Mudflow: Same as 2) ]]
|
||||
local plants = minetest.find_nodes_in_area(minp, maxp, "group:double_plant")
|
||||
for n = 1, #plants do
|
||||
local node = vm:get_node_at(plants[n])
|
||||
local is_top = minetest.get_item_group(node.name, "double_plant") == 2
|
||||
if is_top then
|
||||
local p_pos = area:index(plants[n].x, plants[n].y-1, plants[n].z)
|
||||
if p_pos then
|
||||
node = vm:get_node_at({x=plants[n].x, y=plants[n].y-1, z=plants[n].z})
|
||||
local is_bottom = minetest.get_item_group(node.name, "double_plant") == 1
|
||||
if not is_bottom then
|
||||
p_pos = area:index(plants[n].x, plants[n].y, plants[n].z)
|
||||
data[p_pos] = c_air
|
||||
vm_context.write = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end, 999999999)
|
|
@ -1,7 +1,10 @@
|
|||
-- Check: v7 apple 2320,4,-12558
|
||||
|
||||
-- Check it:
|
||||
-- seed 1, v7 mapgen
|
||||
-- /teleport 14958,8,11370
|
||||
local chance_per_chunk = 5
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 12342
|
||||
local struct_threshold = chance_per_chunk
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
local mcl_mapgen_get_far_node = mcl_mapgen.get_far_node
|
||||
local minetest_log = minetest.log
|
||||
|
@ -44,8 +47,12 @@ mcl_mapgen.register_mapgen(function(minp, maxp, seed)
|
|||
local y = minp.y
|
||||
if y ~= y_wanted then return end
|
||||
|
||||
local pr = PseudoRandom(seed + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
local noise = mcl_structures_get_perlin_noise_level(minp) * noise_multiplier
|
||||
if not noise or (random_number + noise) < struct_threshold then return end
|
||||
|
||||
local x, z = minp.x, minp.z
|
||||
local pr = PseudoRandom(seed)
|
||||
|
||||
-- scan the ocean - it should be the ocean:
|
||||
for i = 1, pr:next(10, 100) do
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
-- Check: v7 apple -21539,27,2404
|
||||
|
||||
local chance_per_chunk = 11
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 999
|
||||
local scanning_ratio = 0.00003
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local scanning_ratio = 0.0003
|
||||
local struct_threshold = chance_per_chunk
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
|
@ -130,7 +132,7 @@ mcl_structures.register_structure({
|
|||
place_on = node_list,
|
||||
flags = "all_floors",
|
||||
fill_ratio = scanning_ratio,
|
||||
y_min = 3,
|
||||
y_min = 1,
|
||||
y_max = mcl_mapgen.overworld.max,
|
||||
height = 1,
|
||||
biomes = not mcl_mapgen.v6 and {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local chance_per_chunk = 60
|
||||
local chance_per_chunk = 20
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 999
|
||||
local scanning_ratio = 0.00001
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local scanning_ratio = 0.0002
|
||||
local struct_threshold = chance_per_chunk
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
|
|
|
@ -12,6 +12,31 @@ local p0 = {
|
|||
|
||||
local schematic = modpath .. "/schematics/mcl_structures_end_exit_portal.mts"
|
||||
|
||||
local dragon_spawn_pos = false
|
||||
local dragon_spawned, portal_generated = false, false
|
||||
|
||||
local function spawn_ender_dragon()
|
||||
local obj = minetest.add_entity(dragon_spawn_pos, "mobs_mc:enderdragon")
|
||||
if not obj then return false end
|
||||
local dragon_entity = obj:get_luaentity()
|
||||
dragon_entity._initial = true
|
||||
dragon_entity._portal_pos = p0
|
||||
return obj
|
||||
end
|
||||
|
||||
local function try_to_spawn_ender_dragon()
|
||||
if spawn_ender_dragon() then
|
||||
dragon_spawned = true
|
||||
return
|
||||
end
|
||||
minetest.after(2, try_to_spawn_ender_dragon)
|
||||
minetest.log("warning", "Ender dragon doesn't want to spawn at "..minetest.pos_to_string(dragon_spawn_pos))
|
||||
end
|
||||
|
||||
if portal_generated and not dragon_spawned then
|
||||
minetest.after(10, try_to_spawn_ender_dragon)
|
||||
end
|
||||
|
||||
local function place(pos, rotation, pr)
|
||||
mcl_structures.place_schematic({pos = pos, schematic = schematic, rotation = rotation, pr = pr})
|
||||
end
|
||||
|
@ -28,6 +53,10 @@ mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context)
|
|||
if minp.z > END_EXIT_PORTAL_POS_Z then return end
|
||||
if maxp.z < END_EXIT_PORTAL_POS_Z then return end
|
||||
|
||||
dragon_spawn_pos = vector.add(p0, vector.new(3, 11, 3))
|
||||
portal_generated = true
|
||||
try_to_spawn_ender_dragon()
|
||||
|
||||
local p = table.copy(p0)
|
||||
|
||||
for y = y2, y1, -1 do
|
||||
|
|
|
@ -4,7 +4,7 @@ local modpath = minetest.get_modpath(modname)
|
|||
local chance_per_block = mcl_structures.from_16x16_to_block_inverted_chance(64)
|
||||
local noise_multiplier = 2
|
||||
local random_offset = 5
|
||||
local struct_threshold = chance_per_block - 1
|
||||
local struct_threshold = chance_per_block
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local min_y = mcl_worlds.layer_to_y(40)
|
||||
|
|
|
@ -3,7 +3,7 @@ local modpath = minetest.get_modpath(modname)
|
|||
|
||||
local chance_per_chunk = 3
|
||||
local random_offset = 1264
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local struct_threshold = chance_per_chunk
|
||||
local noise_params = {
|
||||
offset = 0,
|
||||
scale = 1,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
-- local chance_per_chunk = mcl_structures.from_16x16_to_chunk_inverted_chance(4400)
|
||||
local chance_per_chunk = 100
|
||||
-- Check: v7 apple -27787,31,3115
|
||||
|
||||
local chance_per_chunk = 39
|
||||
local noise_multiplier = 1.4
|
||||
local random_offset = 555
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local struct_threshold = chance_per_chunk
|
||||
local scanning_ratio = 0.0003
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
|
|
@ -337,9 +337,7 @@ function mcl_structures.call_struct(pos, struct_style, rotation, pr, callback)
|
|||
if not rotation then
|
||||
rotation = "random"
|
||||
end
|
||||
if struct_style == "witch_hut" then
|
||||
return mcl_structures.generate_witch_hut(pos, rotation)
|
||||
elseif struct_style == "boulder" then
|
||||
if struct_style == "boulder" then
|
||||
return mcl_structures.generate_boulder(pos, rotation, pr)
|
||||
elseif struct_style == "end_exit_portal" then
|
||||
return mcl_structures.generate_end_exit_portal(pos, rotation, pr, callback)
|
||||
|
@ -385,27 +383,6 @@ function mcl_structures.generate_boulder(pos, rotation, pr)
|
|||
return minetest.place_schematic(newpos, path, rotation) -- don't serialize schematics for registered biome decorations, for MT 5.4.0, https://github.com/minetest/minetest/issues/10995
|
||||
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.get_far_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
|
||||
|
||||
function mcl_structures.generate_witch_hut(pos, rotation, pr)
|
||||
local path = modpath.."/schematics/mcl_structures_witch_hut.mts"
|
||||
mcl_structures.place_schematic(pos, path, rotation, nil, true, nil, hut_placement_callback, pr)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_ice_spike_large(pos, rotation)
|
||||
local path = modpath.."/schematics/mcl_structures_ice_spike_large.mts"
|
||||
return minetest.place_schematic(pos, path, rotation or "random", nil, false) -- don't serialize schematics for registered biome decorations, for MT 5.4.0
|
||||
end
|
||||
|
||||
function mcl_structures.generate_end_exit_portal(pos, rot, pr, callback)
|
||||
local path = modpath.."/schematics/mcl_structures_end_exit_portal.mts"
|
||||
return mcl_structures.place_schematic(pos, path, rot or "0", {["mcl_portals:portal_end"] = "air"}, true, nil, callback)
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local chance_per_chunk = 9
|
||||
-- Check: v7 apple 28530,6,28070
|
||||
-- Check: v7 apple -16343,24,5330
|
||||
|
||||
local chance_per_chunk = 30
|
||||
local noise_multiplier = 1.3
|
||||
local random_offset = 132
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local struct_threshold = chance_per_chunk
|
||||
local scanning_ratio = 0.0003
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local chance_per_chunk = 15
|
||||
-- Check: v7 apple 27576,14,28368
|
||||
-- Check: v7 apple 29570,10,29266
|
||||
|
||||
local chance_per_chunk = 40
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 133
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local struct_threshold = chance_per_chunk
|
||||
local scanning_ratio = 0.00021
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
|
|
|
@ -57,4 +57,4 @@ mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context)
|
|||
end
|
||||
end
|
||||
end
|
||||
end, -1)
|
||||
end, 99999999999999)
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
local chance_per_chunk = 3
|
||||
-- Check: v7 apple 30584,5,30356
|
||||
-- Check: v7 apple 2637,6,-12031
|
||||
-- Check: v7 apple 2644,6,-17968
|
||||
|
||||
local chance_per_chunk = 17
|
||||
local noise_multiplier = -0.9
|
||||
local random_offset = 8
|
||||
local scanning_ratio = 0.01
|
||||
local struct_threshold = chance_per_chunk - 1
|
||||
local struct_threshold = chance_per_chunk
|
||||
|
||||
local mcl_structures_get_perlin_noise_level = mcl_structures.get_perlin_noise_level
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# MCL_Villages version 1.0
|
||||
--------------------------
|
||||
Originally a fork of Rochambeau's "Settlements", fully rewritten for MineClone 5.
|
||||
|
||||
## Using the mod
|
||||
----------------
|
||||
This mod adds villages on world generation.
|
||||
|
||||
## Credits
|
||||
----------
|
||||
* This mod is originally based on "ruins" by BlockMen
|
||||
|
||||
* Completely new schematics for MineClone2:
|
||||
* MysticTempest - CC-BY-SA 4.0
|
||||
|
||||
* Basic conversion of Settlements mod for compatibility with MineClone2: MysticTempest
|
||||
|
||||
* Reimplemention: kay27
|
||||
|
||||
## License
|
||||
----------
|
||||
* License of source code: WTFPL
|
|
@ -1,45 +0,0 @@
|
|||
MCL_Villages:
|
||||
============================
|
||||
A fork of Rochambeau's "Settlements" mod converted for use in MineClone 2.
|
||||
|
||||
--------------
|
||||
Using the mod:
|
||||
--------------
|
||||
This mod adds settlements on world generation.
|
||||
|
||||
And, in Creative Mode; also comes with a debug tool for spawning in villages.
|
||||
|
||||
|
||||
-------------
|
||||
MCL2 Credits:
|
||||
-------------
|
||||
Code forked from: https://github.com/MysticTempest/settlements/tree/mcl_villages
|
||||
Commit: e24b4be
|
||||
================================================================================
|
||||
Basic conversion of Settlements mod for compatibility with MineClone2, plus new schematics: MysticTempest
|
||||
|
||||
Seed-based Village Generation, multi-threading, bugfixes: kay27
|
||||
|
||||
|
||||
|
||||
=========================
|
||||
version: 0.1 alpha
|
||||
|
||||
License of source code: WTFPL
|
||||
-----------------------------
|
||||
(c) Copyright Rochambeau (2018)
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
|
||||
Credits:
|
||||
--------------
|
||||
This mod is based on "ruins" by BlockMen
|
||||
|
||||
Completely new schematics for MineClone2:
|
||||
MysticTempest - CC-BY-SA 4.0
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- initialize settlement_info
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_settlement_info(pr)
|
||||
local count_buildings = {}
|
||||
|
||||
-- count_buildings table reset
|
||||
for k,v in pairs(settlements.schematic_table) do
|
||||
count_buildings[v["name"]] = 0
|
||||
end
|
||||
|
||||
-- randomize number of buildings
|
||||
local number_of_buildings = pr:next(10, 25)
|
||||
local number_built = 1
|
||||
settlements.debug("Village ".. number_of_buildings)
|
||||
|
||||
return count_buildings, number_of_buildings, number_built
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- fill settlement_info
|
||||
--------------------------------------------------------------------------------
|
||||
function settlements.create_site_plan(maxp, minp, pr)
|
||||
local settlement_info = {}
|
||||
local building_all_info
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
-- find center of chunk
|
||||
local center = {
|
||||
x=math.floor((minp.x+maxp.x)/2),
|
||||
y=maxp.y,
|
||||
z=math.floor((minp.z+maxp.z)/2)
|
||||
}
|
||||
-- find center_surface of chunk
|
||||
local center_surface , surface_material = settlements.find_surface(center, true)
|
||||
local chunks = {}
|
||||
chunks[mcl_mapgen.get_chunk_number(center)] = true
|
||||
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
|
||||
-- add settlement to list
|
||||
table.insert(settlements_in_world, center_surface)
|
||||
-- save list to file
|
||||
settlements.save()
|
||||
-- initialize all settlement_info table
|
||||
local count_buildings, number_of_buildings, number_built = settlements.initialize_settlement_info(pr)
|
||||
-- first building is townhall in the center
|
||||
building_all_info = settlements.schematic_table[1]
|
||||
local rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
-- add to settlement info table
|
||||
local index = 1
|
||||
settlement_info[index] = {
|
||||
pos = center_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
--increase index for following buildings
|
||||
index = index + 1
|
||||
-- now some buildings around in a circle, radius = size of town center
|
||||
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
|
||||
-- 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_mapgen.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
|
||||
end
|
||||
end
|
||||
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
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate settlement_info and place schematics
|
||||
-------------------------------------------------------------------------------
|
||||
-- Initialize node
|
||||
local function construct_node(p1, p2, name)
|
||||
local r = minetest.registered_nodes[name]
|
||||
if r then
|
||||
if r.on_construct then
|
||||
local nodes = minetest.find_nodes_in_area(p1, p2, name)
|
||||
for p=1, #nodes do
|
||||
local pos = nodes[p]
|
||||
r.on_construct(pos)
|
||||
end
|
||||
return nodes
|
||||
end
|
||||
minetest.log("warning", "[mcl_villages] No on_construct defined for node name " .. name)
|
||||
return
|
||||
end
|
||||
minetest.log("warning", "[mcl_villages] Attempt to 'construct' inexistant nodes: " .. name)
|
||||
end
|
||||
local function init_nodes(p1, p2, size, rotation, pr)
|
||||
construct_node(p1, p2, "mcl_itemframes:item_frame")
|
||||
construct_node(p1, p2, "mcl_furnaces:furnace")
|
||||
construct_node(p1, p2, "mcl_anvils:anvil")
|
||||
|
||||
local nodes = construct_node(p1, p2, "mcl_chests:chest")
|
||||
if nodes and #nodes > 0 then
|
||||
for p=1, #nodes do
|
||||
local pos = nodes[p]
|
||||
settlements.fill_chest(pos, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
function settlements.place_schematics(settlement_info, pr)
|
||||
local building_all_info
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
for j, schem in ipairs(settlements.schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
building_all_info = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local pos = settlement_info[i]["pos"]
|
||||
local rotation = settlement_info[i]["rotat"]
|
||||
-- get building node material for better integration to surrounding
|
||||
local platform_material = settlement_info[i]["surface_mat"]
|
||||
--platform_material_name = minetest.get_name_from_content_id(platform_material)
|
||||
-- pick random material
|
||||
--local material = wallmaterial[pr:next(1,#wallmaterial)]
|
||||
--
|
||||
local building = building_all_info["mts"]
|
||||
local replace_wall = building_all_info["rplc"]
|
||||
-- schematic conversion to lua
|
||||
local schem_lua = minetest.serialize_schematic(building,
|
||||
"lua",
|
||||
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return schematic"
|
||||
schem_lua = schem_lua:gsub("mcl_core:stonebrickcarved", "mcl_villages:stonebrickcarved")
|
||||
-- replace material
|
||||
if replace_wall then
|
||||
--Note, block substitution isn't matching node names exactly; so nodes that are to be substituted that have the same prefixes cause bugs.
|
||||
-- Example: Attempting to swap out 'mcl_core:stonebrick'; which has multiple, additional sub-variants: (carved, cracked, mossy). Will currently cause issues, so leaving disabled.
|
||||
if platform_material == "mcl_core:snow" or platform_material == "mcl_core:dirt_with_grass_snow" or platform_material == "mcl_core:podzol" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:tree", "mcl_core:sprucetree")
|
||||
schem_lua = schem_lua:gsub("mcl_core:wood", "mcl_core:sprucewood")
|
||||
--schem_lua = schem_lua:gsub("mcl_fences:fence", "mcl_fences:spruce_fence")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:slab_wood_top", "mcl_stairs:slab_sprucewood_top")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:stair_wood", "mcl_stairs:stair_sprucewood")
|
||||
--schem_lua = schem_lua:gsub("mesecons_pressureplates:pressure_plate_wood_off", "mesecons_pressureplates:pressure_plate_sprucewood_off")
|
||||
elseif platform_material == "mcl_core:sand" or platform_material == "mcl_core:redsand" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:tree", "mcl_core:sandstonecarved")
|
||||
schem_lua = schem_lua:gsub("mcl_core:cobble", "mcl_core:sandstone")
|
||||
schem_lua = schem_lua:gsub("mcl_core:wood", "mcl_core:sandstonesmooth")
|
||||
--schem_lua = schem_lua:gsub("mcl_fences:fence", "mcl_fences:birch_fence")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:slab_wood_top", "mcl_stairs:slab_birchwood_top")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:stair_wood", "mcl_stairs:stair_birchwood")
|
||||
--schem_lua = schem_lua:gsub("mesecons_pressureplates:pressure_plate_wood_off", "mesecons_pressureplates:pressure_plate_birchwood_off")
|
||||
--schem_lua = schem_lua:gsub("mcl_stairs:stair_stonebrick", "mcl_stairs:stair_redsandstone")
|
||||
--schem_lua = schem_lua:gsub("mcl_core:stonebrick", "mcl_core:redsandstonesmooth")
|
||||
schem_lua = schem_lua:gsub("mcl_core:brick_block", "mcl_core:redsandstone")
|
||||
end
|
||||
end
|
||||
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass", platform_material)
|
||||
|
||||
--[[ Disable special junglewood for now.
|
||||
-- special material for spawning npcs
|
||||
schem_lua = schem_lua:gsub("mcl_core:junglewood", "settlements:junglewood")
|
||||
--]]
|
||||
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_wood_outer", "mcl_stairs:slab_wood")
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_stone_rough_outer", "air")
|
||||
|
||||
-- format schematic string
|
||||
local schematic = loadstring(schem_lua)()
|
||||
-- build foundation for the building an make room above
|
||||
-- place schematic
|
||||
mcl_structures.place_schematic({
|
||||
pos = pos,
|
||||
schematic = schematic,
|
||||
rotation = rotation,
|
||||
force_placement = true,
|
||||
on_place = init_nodes,
|
||||
pr = pr,
|
||||
})
|
||||
end
|
||||
end
|
|
@ -1,81 +0,0 @@
|
|||
-- switch for debugging
|
||||
function settlements.debug(message)
|
||||
-- minetest.chat_send_all(message)
|
||||
-- minetest.log("warning", "[mcl_villages] "..message)
|
||||
minetest.log("verbose", "[mcl_villages] "..message)
|
||||
end
|
||||
|
||||
--[[ Manually set in 'buildings.lua'
|
||||
-- material to replace cobblestone with
|
||||
local wallmaterial = {
|
||||
"mcl_core:junglewood",
|
||||
"mcl_core:sprucewood",
|
||||
"mcl_core:wood",
|
||||
"mcl_core:birchwood",
|
||||
"mcl_core:acaciawood",
|
||||
"mcl_core:stonebrick",
|
||||
"mcl_core:cobble",
|
||||
"mcl_core:sandstonecarved",
|
||||
"mcl_core:sandstone",
|
||||
"mcl_core:sandstonesmooth2"
|
||||
}
|
||||
--]]
|
||||
settlements.surface_mat = {}
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.grundstellungen()
|
||||
settlements.surface_mat = settlements.Set {
|
||||
"mcl_core:dirt_with_grass",
|
||||
--"mcl_core:dry_dirt_with_grass",
|
||||
"mcl_core:dirt_with_grass_snow",
|
||||
--"mcl_core:dirt_with_dry_grass",
|
||||
"mcl_core:podzol",
|
||||
"mcl_core:sand",
|
||||
"mcl_core:redsand",
|
||||
--"mcl_core:silver_sand",
|
||||
"mcl_core:snow"
|
||||
}
|
||||
end
|
||||
--
|
||||
-- possible surfaces where buildings can be built
|
||||
--
|
||||
|
||||
--
|
||||
-- path to schematics
|
||||
--
|
||||
schem_path = settlements.modpath.."/schematics/"
|
||||
--
|
||||
-- list of schematics
|
||||
--
|
||||
local basic_pseudobiome_villages = minetest.settings:get_bool("basic_pseudobiome_villages", true)
|
||||
|
||||
settlements.schematic_table = {
|
||||
{name = "large_house", mts = schem_path.."large_house.mts", hwidth = 11, hdepth = 12, hheight = 9, hsize = 14, max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "blacksmith", mts = schem_path.."blacksmith.mts", hwidth = 7, hdepth = 7, hheight = 13, hsize = 13, max_num = 0.055, rplc = basic_pseudobiome_villages },
|
||||
{name = "butcher", mts = schem_path.."butcher.mts", hwidth = 11, hdepth = 8, hheight = 10, hsize = 14, max_num = 0.03 , rplc = basic_pseudobiome_villages },
|
||||
{name = "church", mts = schem_path.."church.mts", hwidth = 13, hdepth = 13, hheight = 14, hsize = 15, max_num = 0.04 , rplc = basic_pseudobiome_villages },
|
||||
{name = "farm", mts = schem_path.."farm.mts", hwidth = 7, hdepth = 7, hheight = 13, hsize = 13, max_num = 0.1 , rplc = basic_pseudobiome_villages },
|
||||
{name = "lamp", mts = schem_path.."lamp.mts", hwidth = 3, hdepth = 3, hheight = 13, hsize = 10, max_num = 0.1 , rplc = false },
|
||||
{name = "library", mts = schem_path.."library.mts", hwidth = 12, hdepth = 12, hheight = 8, hsize = 13, max_num = 0.04 , rplc = basic_pseudobiome_villages },
|
||||
{name = "medium_house", mts = schem_path.."medium_house.mts", hwidth = 8, hdepth = 12, hheight = 8, hsize = 14, max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "small_house", mts = schem_path.."small_house.mts", hwidth = 9, hdepth = 7, hheight = 8, hsize = 13, max_num = 0.7 , rplc = basic_pseudobiome_villages },
|
||||
{name = "tavern", mts = schem_path.."tavern.mts", hwidth = 11, hdepth = 10, hheight = 10, hsize = 13, max_num = 0.050, rplc = basic_pseudobiome_villages },
|
||||
{name = "well", mts = schem_path.."well.mts", hwidth = 6, hdepth = 8, hheight = 6, hsize = 10, max_num = 0.045, rplc = basic_pseudobiome_villages },
|
||||
}
|
||||
|
||||
--
|
||||
-- list of settlements, load on server start up
|
||||
--
|
||||
settlements_in_world = {}
|
||||
--
|
||||
--
|
||||
-- maximum allowed difference in height for building a sttlement
|
||||
--
|
||||
max_height_difference = 56
|
||||
--
|
||||
--
|
||||
--
|
||||
half_map_chunk_size = 40
|
||||
--quarter_map_chunk_size = 20
|
|
@ -1,59 +0,0 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- function to fill empty space below baseplate when building on a hill
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.ground(pos, pr) -- role model: Wendelsteinkircherl, Brannenburg
|
||||
local p2 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local mat = "mcl_core:dirt"
|
||||
p2.y = p2.y-1
|
||||
while true do
|
||||
cnt = cnt+1
|
||||
if cnt > 20 then break end
|
||||
if cnt>pr:next(2,4) then
|
||||
mat = "mcl_core:stone"
|
||||
end
|
||||
minetest.swap_node(p2, {name=mat})
|
||||
p2.y = p2.y-1
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function clear space above baseplate
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.terraform(settlement_info, pr)
|
||||
local fheight, fwidth, fdepth, schematic_data
|
||||
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
-- pick right schematic_info to current built_house
|
||||
for j, schem in ipairs(settlements.schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
schematic_data = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
local pos = settlement_info[i]["pos"]
|
||||
if settlement_info[i]["rotat"] == "0" or settlement_info[i]["rotat"] == "180" then
|
||||
fwidth = schematic_data["hwidth"]
|
||||
fdepth = schematic_data["hdepth"]
|
||||
else
|
||||
fwidth = schematic_data["hdepth"]
|
||||
fdepth = schematic_data["hwidth"]
|
||||
end
|
||||
--fheight = schematic_data["hheight"] * 3 -- remove trees and leaves above
|
||||
fheight = schematic_data["hheight"] -- remove trees and leaves above
|
||||
--
|
||||
-- now that every info is available -> create platform and clear space above
|
||||
--
|
||||
for xi = 0,fwidth-1 do
|
||||
for zi = 0,fdepth-1 do
|
||||
for yi = 0,fheight *3 do
|
||||
if yi == 0 then
|
||||
local p = {x=pos.x+xi, y=pos.y, z=pos.z+zi}
|
||||
settlements.ground(p, pr)
|
||||
else
|
||||
minetest.swap_node({x=pos.x+xi, y=pos.y+yi, z=pos.z+zi},{name="air"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +1,379 @@
|
|||
settlements = {}
|
||||
settlements.modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
mcl_villages = {}
|
||||
local chance_per_chunk = 90
|
||||
local chunk_offset_top = 15
|
||||
local chunk_offset_bottom = 3
|
||||
local max_height_difference = 12
|
||||
local minp_min = -64
|
||||
local noise_multiplier = 1
|
||||
local random_offset = 1
|
||||
local random_multiply = 19
|
||||
local struct_threshold = chance_per_chunk
|
||||
local noise_params = {
|
||||
offset = 0,
|
||||
scale = 2,
|
||||
spread = {
|
||||
x = mcl_mapgen.CS_NODES * chance_per_chunk,
|
||||
y = mcl_mapgen.CS_NODES * chance_per_chunk,
|
||||
z = mcl_mapgen.CS_NODES * chance_per_chunk,
|
||||
},
|
||||
seed = 842458,
|
||||
octaves = 2,
|
||||
persistence = 0.5,
|
||||
}
|
||||
local perlin_noise
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
local S = minetest.get_translator(modname)
|
||||
local basic_pseudobiome_villages = minetest.settings:get_bool("basic_pseudobiome_villages", true)
|
||||
local schem_path = modpath .. "/schematics/"
|
||||
local schematic_table = {
|
||||
{name = "large_house", mts = schem_path.."large_house.mts", max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "blacksmith", mts = schem_path.."blacksmith.mts", max_num = 0.055, rplc = basic_pseudobiome_villages },
|
||||
{name = "butcher", mts = schem_path.."butcher.mts", max_num = 0.03 , rplc = basic_pseudobiome_villages },
|
||||
{name = "church", mts = schem_path.."church.mts", max_num = 0.04 , rplc = basic_pseudobiome_villages },
|
||||
{name = "farm", mts = schem_path.."farm.mts", max_num = 0.1 , rplc = basic_pseudobiome_villages },
|
||||
{name = "lamp", mts = schem_path.."lamp.mts", max_num = 0.1 , rplc = false },
|
||||
{name = "library", mts = schem_path.."library.mts", max_num = 0.04 , rplc = basic_pseudobiome_villages },
|
||||
{name = "medium_house", mts = schem_path.."medium_house.mts", max_num = 0.08 , rplc = basic_pseudobiome_villages },
|
||||
{name = "small_house", mts = schem_path.."small_house.mts", max_num = 0.7 , rplc = basic_pseudobiome_villages },
|
||||
{name = "tavern", mts = schem_path.."tavern.mts", max_num = 0.050, rplc = basic_pseudobiome_villages },
|
||||
{name = "well", mts = schem_path.."well.mts", max_num = 0.045, rplc = basic_pseudobiome_villages },
|
||||
}
|
||||
local surface_mat = {
|
||||
["mcl_core:dirt_with_dry_grass"] = { top = "mcl_core:dirt", bottom = "mcl_core:stone" },
|
||||
["mcl_core:dirt_with_grass"] = { top = "mcl_core:dirt", bottom = "mcl_core:stone" },
|
||||
["mcl_core:dirt_with_grass_snow"] = { top = "mcl_core:dirt", bottom = "mcl_core:stone" },
|
||||
["mcl_core:podzol"] = { top = "mcl_core:podzol", bottom = "mcl_core:stone" },
|
||||
["mcl_core:redsand"] = { top = "mcl_core:redsand", bottom = "mcl_core:redsandstone" },
|
||||
["mcl_core:sand"] = { top = "mcl_core:sand", bottom = "mcl_core:sandstone" },
|
||||
["mcl_core:snow"] = { top = "mcl_core:dirt", bottom = "mcl_core:stone" },
|
||||
}
|
||||
local storage = minetest.get_mod_storage()
|
||||
local villages = minetest.deserialize(storage:get_string("villages") or "return {}") or {}
|
||||
local minetest_get_spawn_level = minetest.get_spawn_level
|
||||
local minetest_get_node = minetest.get_node
|
||||
local minetest_find_nodes_in_area = minetest.find_nodes_in_area
|
||||
local minetest_get_perlin = minetest.get_perlin
|
||||
local math_pi = math.pi
|
||||
local math_cos = math.cos
|
||||
local math_sin = math.sin
|
||||
local math_min = math.min
|
||||
local math_max = math.max
|
||||
local math_floor = math.floor
|
||||
local math_ceil = math.ceil
|
||||
local string_find = string.find
|
||||
local minetest_swap_node = minetest.swap_node
|
||||
local minetest_registered_nodes = minetest.registered_nodes
|
||||
local minetest_bulk_set_node = minetest.bulk_set_node
|
||||
local air_offset = chunk_offset_top - 1
|
||||
local ground_offset = chunk_offset_bottom + 1
|
||||
local surface_search_list = {}
|
||||
for k, _ in pairs(surface_mat) do
|
||||
table.insert(surface_search_list, k)
|
||||
end
|
||||
|
||||
dofile(settlements.modpath.."/const.lua")
|
||||
dofile(settlements.modpath.."/utils.lua")
|
||||
dofile(settlements.modpath.."/foundation.lua")
|
||||
dofile(settlements.modpath.."/buildings.lua")
|
||||
dofile(settlements.modpath.."/paths.lua")
|
||||
--dofile(settlements.modpath.."/convert_lua_mts.lua")
|
||||
--
|
||||
-- load settlements on server
|
||||
--
|
||||
settlements_in_world = settlements.load()
|
||||
settlements.grundstellungen()
|
||||
local function math_round(x)
|
||||
return (x < 0) and math_ceil(x - 0.5) or math_floor(x + 0.5)
|
||||
end
|
||||
|
||||
local function find_surface(pos, minp, maxp)
|
||||
local x, z = pos.x, pos.z
|
||||
local y_top = maxp.y
|
||||
local y_max = y_top - air_offset
|
||||
if #minetest_find_nodes_in_area({x=x, y=y_max, z=z}, {x=x, y=y_top, z=z}, "air") < chunk_offset_top then return end
|
||||
y_max = y_max - 1
|
||||
local y_bottom = minp.y
|
||||
local y_min = y_bottom + chunk_offset_bottom
|
||||
local nodes = minetest_find_nodes_in_area({x=x, y=y_min, z=z}, {x=x, y=y_max, z=z}, surface_search_list)
|
||||
for _, surface_pos in pairs(nodes) do
|
||||
local node_name_from_above = minetest_get_node({x=surface_pos.x, y=surface_pos.y+1, z=surface_pos.z}).name
|
||||
if string_find(node_name_from_above, "air" )
|
||||
or string_find(node_name_from_above, "snow" )
|
||||
or string_find(node_name_from_above, "fern" )
|
||||
or string_find(node_name_from_above, "flower")
|
||||
or string_find(node_name_from_above, "bush" )
|
||||
or string_find(node_name_from_above, "tree" )
|
||||
or string_find(node_name_from_above, "grass" )
|
||||
then
|
||||
return surface_pos, minetest_get_node(surface_pos).name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_treasures(pr)
|
||||
local loottable = {{
|
||||
stacks_min = 3,
|
||||
stacks_max = 8,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:diamond" , weight = 3, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:iron_ingot" , weight = 10, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_core:gold_ingot" , weight = 5, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_farming:bread" , weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:apple" , weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_tools:pick_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_tools:sword_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_armor:chestplate_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_armor:helmet_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_armor:leggings_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_armor:boots_iron" , weight = 5, },
|
||||
{ itemstring = "mcl_core:obsidian" , weight = 5, amount_min = 3, amount_max = 7 },
|
||||
{ itemstring = "mcl_core:sapling" , weight = 5, amount_min = 3, amount_max = 7 },
|
||||
{ itemstring = "mcl_mobitems:saddle" , weight = 3, },
|
||||
{ itemstring = "mobs_mc:iron_horse_armor" , weight = 1, },
|
||||
{ itemstring = "mobs_mc:gold_horse_armor" , weight = 1, },
|
||||
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 1, },
|
||||
}
|
||||
}}
|
||||
local items = mcl_loot.get_multi_loot(loottable, pr)
|
||||
return items
|
||||
end
|
||||
|
||||
local function fill_chest(pos, pr)
|
||||
local meta = minetest.get_meta(pos)
|
||||
minetest.registered_nodes["mcl_chests:chest_small"].on_construct(pos)
|
||||
local inv = minetest.get_inventory( {type="node", pos=pos} )
|
||||
local items = get_treasures(pr)
|
||||
mcl_loot.fill_inventory(inv, "main", items, pr)
|
||||
end
|
||||
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
|
||||
local function get_random_rotation(pr)
|
||||
return possible_rotations[pr:next(1, #possible_rotations)]
|
||||
end
|
||||
|
||||
local function create_site_plan(minp, maxp, pr)
|
||||
local plan = {}
|
||||
local building_all_info
|
||||
local center = vector.add(minp, mcl_mapgen.HALF_CS_NODES)
|
||||
local center_surface, surface_material = find_surface(center, minp, maxp)
|
||||
if not center_surface then return end
|
||||
|
||||
local number_of_buildings = pr:next(10, 25)
|
||||
local shuffle = {}
|
||||
local count_buildings = {}
|
||||
for i = 1, #schematic_table do
|
||||
shuffle[i] = i
|
||||
count_buildings[i] = 0
|
||||
end
|
||||
for i = #shuffle, 2, -1 do
|
||||
local j = pr:next(1, i)
|
||||
shuffle[i], shuffle[j] = shuffle[j], shuffle[i]
|
||||
end
|
||||
local number_built = 1
|
||||
local shuffle_index = pr:next(1, #schematic_table)
|
||||
|
||||
-- first building is townhall in the center
|
||||
plan[#plan + 1] = {
|
||||
pos = center_surface,
|
||||
building = schematic_table[shuffle_index],
|
||||
rotation = get_random_rotation(pr),
|
||||
surface_mat = surface_material,
|
||||
}
|
||||
count_buildings[1] = count_buildings[1] + 1
|
||||
-- now some buildings around in a circle, radius = size of town center
|
||||
local x, z, r = center_surface.x, center_surface.z, schematic_table[1].hsize
|
||||
-- draw j circles around center and increase radius by random(2, 5)
|
||||
for k = 1, 20 do
|
||||
-- set position on imaginary circle
|
||||
for j = 0, 360, 15 do
|
||||
local angle = j * math_pi / 180
|
||||
local pos_surface, surface_material = find_surface(
|
||||
{
|
||||
x = math_round(x + r * math_cos(angle)),
|
||||
z = math_round(z + r * math_sin(angle))
|
||||
},
|
||||
minp,
|
||||
maxp
|
||||
)
|
||||
if pos_surface then
|
||||
shuffle_index = (shuffle_index % (#schematic_table)) + 1
|
||||
local schematic_index = shuffle[shuffle_index]
|
||||
local schematic = schematic_table[schematic_index]
|
||||
if count_buildings[schematic_index] < schematic.max_num * number_of_buildings then
|
||||
local hsize2 = schematic.hsize^2
|
||||
local is_distance_ok = true
|
||||
for _, built_house in pairs(plan) do
|
||||
local pos = built_house.pos
|
||||
local building = built_house.building
|
||||
local distance2 = (pos_surface.x - pos.x)^2 + (pos_surface.z - pos.z)^2
|
||||
if distance2 < building.hsize^2 or distance2 < hsize2 then
|
||||
is_distance_ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if is_distance_ok then
|
||||
plan[#plan + 1] = {
|
||||
pos = pos_surface,
|
||||
building = schematic,
|
||||
rotation = get_random_rotation(pr),
|
||||
surface_mat = surface_material,
|
||||
}
|
||||
count_buildings[schematic_index] = count_buildings[schematic_index] + 1
|
||||
number_built = number_built + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if number_built >= number_of_buildings then
|
||||
break
|
||||
end
|
||||
end
|
||||
if number_built >= number_of_buildings then
|
||||
break
|
||||
end
|
||||
r = r + pr:next(2, 5)
|
||||
end
|
||||
return plan
|
||||
end
|
||||
|
||||
local function ground(pos1, pos2, minp, maxp, pr, mat)
|
||||
local pos1, pos2 = pos1, pos2
|
||||
local x1, x2, z1, z2, y = pos1.x, pos2.x, pos1.z, pos2.z, pos1.y - 1
|
||||
local pos_list_dirt = {}
|
||||
local pos_list_stone = {}
|
||||
for x0 = x1, x2 do
|
||||
for z0 = z1, z2 do
|
||||
local finish = false
|
||||
local y1 = y - pr:next(2, 4)
|
||||
for y0 = y, y1, -1 do
|
||||
local p0 = {x = x0, y = y0, z = z0}
|
||||
local node = minetest_get_node(p0)
|
||||
local node_name = node.name
|
||||
if node_name ~= "air" and not string_find(node_name, "water") and not string_find(node_name, "flower") then
|
||||
finish = true
|
||||
break
|
||||
end
|
||||
pos_list_dirt[#pos_list_dirt + 1] = p0
|
||||
end
|
||||
if not finish then
|
||||
for y0 = y1 - 1, math_max(minp.y, y - pr:next(17, 27)), -1 do
|
||||
local p0 = {x = x0, y = y0, z = z0}
|
||||
local node = minetest_get_node(p0)
|
||||
local node_name = node.name
|
||||
if node_name ~= "air" and not string_find(node_name, "water") and not string_find(node_name, "flower") then
|
||||
break
|
||||
end
|
||||
pos_list_stone[#pos_list_stone + 1] = p0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest_bulk_set_node(pos_list_dirt, {name = surface_mat[mat].top})
|
||||
minetest_bulk_set_node(pos_list_stone, {name = surface_mat[mat].bottom})
|
||||
end
|
||||
|
||||
local function terraform(plan, minp, maxp, pr)
|
||||
local fheight, fwidth, fdepth, schematic_data, pos, rotation, swap_wd, build_material
|
||||
for _, built_house in pairs(plan) do
|
||||
schematic_data = built_house.building
|
||||
pos = built_house.pos
|
||||
rotation = built_house.rotation
|
||||
build_material = built_house.surface_mat
|
||||
swap_wd = rotation == "90" or rotation == "270"
|
||||
fwidth = swap_wd and schematic_data.hdepth or schematic_data.hwidth
|
||||
fdepth = swap_wd and schematic_data.hwidth or schematic_data.hdepth
|
||||
fheight = schematic_data.hheight
|
||||
local pos2 = {
|
||||
x = pos.x + fwidth - 1,
|
||||
y = math_min(pos.y + fheight + 4, maxp.y),
|
||||
z = pos.z + fdepth - 1
|
||||
}
|
||||
ground(pos, {x = pos2.x, y = pos.y + 1, z = pos2.z}, minp, maxp, pr, build_material)
|
||||
local node_list = {}
|
||||
for xi = pos.x, pos2.x do
|
||||
for zi = pos.z, pos2.z do
|
||||
for yi = pos.y + 1, pos2.y do
|
||||
node_list[#node_list + 1] = {x = xi, y = yi, z = zi}
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest_bulk_set_node(node_list, {name = "air"})
|
||||
end
|
||||
end
|
||||
|
||||
local function paths(plan, minp, maxp)
|
||||
local starting_point = find_surface({x = plan[1].pos.x + 2, z = plan[1].pos.z + 2}, minp, maxp)
|
||||
if not starting_point then return end
|
||||
starting_point.y = starting_point.y + 1
|
||||
for i = 2, #plan do
|
||||
local p = plan[i]
|
||||
local end_point = p.pos
|
||||
end_point.y = end_point.y + 1
|
||||
local path = minetest.find_path(starting_point, end_point, mcl_mapgen.CS_NODES, 2, 2, "A*_noprefetch")
|
||||
if path then
|
||||
for _, pos in pairs(path) do
|
||||
pos.y = pos.y - 1
|
||||
local surface_mat = minetest.get_node(pos).name
|
||||
if surface_mat == "mcl_core:sand" or surface_mat == "mcl_core:redsand" then
|
||||
minetest.swap_node(pos, {name = "mcl_core:sandstonesmooth2"})
|
||||
else
|
||||
minetest.swap_node(pos, {name = "mcl_core:grass_path"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function init_nodes(p1, rotation, pr, size)
|
||||
local p2 = vector.subtract(vector.add(p1, size), 1)
|
||||
local nodes = minetest.find_nodes_in_area(p1, p2, {"mcl_itemframes:item_frame", "mcl_furnaces:furnace", "mcl_anvils:anvil", "mcl_chests:chest", "mcl_villages:stonebrickcarved"})
|
||||
for _, pos in pairs(nodes) do
|
||||
local name = minetest_get_node(pos).name
|
||||
local def = minetest_registered_nodes[minetest_get_node(pos).name]
|
||||
def.on_construct(pos)
|
||||
if name == "mcl_chests:chest" then
|
||||
minetest_swap_node(pos, {name = "mcl_chests:chest_small"})
|
||||
fill_chest(pos, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function place_schematics(plan, pr)
|
||||
for _, built_house in pairs(plan) do
|
||||
local pos = built_house.pos
|
||||
local rotation = built_house.rotation
|
||||
local platform_material = built_house.surface_mat
|
||||
local replace_wall = built_house.building.rplc
|
||||
local schem_lua = built_house.building.preloaded_schematic
|
||||
if replace_wall then
|
||||
--Note, block substitution isn't matching node names exactly; so nodes that are to be substituted that have the same prefixes cause bugs.
|
||||
-- Example: Attempting to swap out 'mcl_core:stonebrick'; which has multiple, additional sub-variants: (carved, cracked, mossy). Will currently cause issues, so leaving disabled.
|
||||
if platform_material == "mcl_core:snow" or platform_material == "mcl_core:dirt_with_grass_snow" or platform_material == "mcl_core:podzol" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:tree", "mcl_core:sprucetree")
|
||||
schem_lua = schem_lua:gsub("mcl_core:wood", "mcl_core:sprucewood")
|
||||
elseif platform_material == "mcl_core:sand" or platform_material == "mcl_core:redsand" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:tree", "mcl_core:sandstonecarved")
|
||||
schem_lua = schem_lua:gsub("mcl_core:cobble", "mcl_core:sandstone")
|
||||
schem_lua = schem_lua:gsub("mcl_core:wood", "mcl_core:sandstonesmooth")
|
||||
schem_lua = schem_lua:gsub("mcl_core:brick_block", "mcl_core:redsandstone")
|
||||
end
|
||||
end
|
||||
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass", platform_material)
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_wood_outer", "mcl_stairs:slab_wood")
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_stone_rough_outer", "air")
|
||||
|
||||
local schematic = loadstring(schem_lua)()
|
||||
-- build foundation for the building an make room above
|
||||
-- place schematic
|
||||
mcl_structures.place_schematic({
|
||||
pos = pos,
|
||||
schematic = schematic,
|
||||
rotation = rotation,
|
||||
on_placed = init_nodes,
|
||||
pr = pr,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- register block for npc spawn
|
||||
--
|
||||
local function spawn_villager(pos)
|
||||
minetest.add_entity({x = pos.x, y = pos.y + 1, z = pos.z}, "mobs_mc:villager")
|
||||
end
|
||||
minetest.register_node("mcl_villages:stonebrickcarved", {
|
||||
description = ("Chiseled Stone Village Bricks"),
|
||||
description = S("Chiseled Stone Village Bricks"),
|
||||
_doc_items_longdesc = doc.sub.items.temp.build,
|
||||
tiles = {"mcl_core_stonebrick_carved.png"},
|
||||
stack_max = 64,
|
||||
|
@ -30,93 +383,142 @@ minetest.register_node("mcl_villages:stonebrickcarved", {
|
|||
is_ground_content = false,
|
||||
_mcl_blast_resistance = 6,
|
||||
_mcl_hardness = 1.5,
|
||||
on_construct = spawn_villager,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Spawn villagers",
|
||||
nodenames = {"mcl_villages:stonebrickcarved"},
|
||||
interval = 60,
|
||||
chance = 3,
|
||||
action = function(pos, node)
|
||||
-- check the space above
|
||||
local p = table.copy(pos)
|
||||
p.y = p.y + 1
|
||||
if minetest_get_node(p).name ~= "air" then return end
|
||||
p.y = p.y + 1
|
||||
if minetest_get_node(p).name ~= "air" then return end
|
||||
p.y = p.y - 1
|
||||
local villagers_counter = 0
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(p, 40)) do
|
||||
local lua_entity = obj:get_luaentity()
|
||||
if luaentity and luaentity.name == "mobs_mc:villager" then
|
||||
villagers_counter = villagers_counter + 1
|
||||
if villagers_counter > 7 then return end
|
||||
end
|
||||
end
|
||||
spawn_villager(pos)
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
--[[ Enable for testing, but use MineClone2's own spawn code if/when merging.
|
||||
--
|
||||
-- register inhabitants
|
||||
--
|
||||
if minetest.get_modpath("mobs_mc") then
|
||||
mobs:register_spawn("mobs_mc:villager", --name
|
||||
{"mcl_core:stonebrickcarved"}, --nodes
|
||||
15, --max_light
|
||||
0, --min_light
|
||||
20, --chance
|
||||
7, --active_object_count
|
||||
31000, --max_height
|
||||
nil) --day_toggle
|
||||
end
|
||||
--]]
|
||||
|
||||
--
|
||||
-- on map generation, try to build a settlement
|
||||
--
|
||||
local function build_a_settlement(minp, maxp, blockseed)
|
||||
minetest.log("action","[mcl_villages] Building village at mapchunk " .. minetest.pos_to_string(minp) .. "..." .. minetest.pos_to_string(maxp) .. ", blockseed = " .. tostring(blockseed))
|
||||
local pr = PseudoRandom(blockseed)
|
||||
|
||||
-- fill settlement_info with buildings and their data
|
||||
local settlement_info = settlements.create_site_plan(maxp, minp, pr)
|
||||
if not settlement_info then return end
|
||||
|
||||
-- evaluate settlement_info and prepair terrain
|
||||
settlements.terraform(settlement_info, pr)
|
||||
|
||||
-- evaluate settlement_info and build paths between buildings
|
||||
settlements.paths(settlement_info)
|
||||
|
||||
-- evaluate settlement_info and place schematics
|
||||
settlements.place_schematics(settlement_info, pr)
|
||||
local function build_a_village(minp, maxp, pr, placer)
|
||||
minetest.log("action","[mcl_villages] Building village at mapchunk " .. minetest.pos_to_string(minp) .. "..." .. minetest.pos_to_string(maxp))
|
||||
local pr = pr or PseudoRandom(mcl_mapgen.get_block_seed3(minp))
|
||||
local plan = create_site_plan(minp, maxp, pr)
|
||||
if not plan then
|
||||
if placer then
|
||||
if placer:is_player() then
|
||||
minetest.chat_send_player(placer:get_player_name(), S("Map chunk @1 to @2 is not suitable for placing villages.", minetest.pos_to_string(minp), minetest.pos_to_string(maxp)))
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
paths(plan, minp, maxp)
|
||||
terraform(plan, minp, maxp, pr)
|
||||
place_schematics(plan, pr)
|
||||
villages[#villages + 1] = minp
|
||||
storage:set_string("villages", minetest.serialize(villages))
|
||||
end
|
||||
|
||||
-- Disable natural generation in singlenode.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if mg_name ~= "singlenode" then
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, blockseed)
|
||||
-- local str1 = (maxp.y >= 0 and blockseed % 77 == 17) and "YES" or "no"
|
||||
-- minetest.log("action","[mcl_villages] " .. str1 .. ": minp=" .. minetest.pos_to_string(minp) .. ", maxp=" .. minetest.pos_to_string(maxp) .. ", blockseed=" .. tostring(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
|
||||
|
||||
-- don't build settlements on (too) uneven terrain
|
||||
|
||||
-- lame and quick replacement of `heightmap` by kay27 - we maybe need to restore `heightmap` analysis if there will be a way for the engine to avoid cavegen conflicts:
|
||||
--------------------------------------------------------------------------
|
||||
local height_difference, min, max
|
||||
local pr1=PseudoRandom(blockseed)
|
||||
for i=1,pr1:next(5,10) do
|
||||
local x = pr1:next(0, 40) + minp.x + 19
|
||||
local z = pr1:next(0, 40) + minp.z + 19
|
||||
local y = minetest_get_spawn_level(x, z)
|
||||
if not y then return end
|
||||
if y < (min or y+1) then min = y end
|
||||
if y > (max or y-1) then max = y end
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local scan_last_node = mcl_mapgen.LAST_BLOCK * mcl_mapgen.BS - 1
|
||||
local scan_offset = mcl_mapgen.BS
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, chunkseed)
|
||||
if minp.y < minp_min then return end
|
||||
local pr = PseudoRandom(chunkseed * random_multiply + random_offset)
|
||||
local random_number = pr:next(1, chance_per_chunk)
|
||||
perlin_noise = perlin_noise or minetest_get_perlin(noise_params)
|
||||
local noise = perlin_noise:get_3d(minp) * noise_multiplier
|
||||
if (random_number + noise) < struct_threshold then return end
|
||||
local min, max = 9999999, -9999999
|
||||
for i = 1, pr:next(5,10) do
|
||||
local surface_point = find_surface(
|
||||
vector.add(
|
||||
vector.new(
|
||||
pr:next(scan_offset, scan_last_node),
|
||||
0,
|
||||
pr:next(scan_offset, scan_last_node)
|
||||
),
|
||||
minp
|
||||
),
|
||||
minp,
|
||||
maxp
|
||||
)
|
||||
if not surface_point then return end
|
||||
local y = surface_point.y
|
||||
min = math_min(y, min)
|
||||
max = math_max(y, max)
|
||||
end
|
||||
height_difference = max - min + 1
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
local height_difference = max - min
|
||||
if height_difference > max_height_difference then return end
|
||||
|
||||
build_a_settlement(minp, maxp, blockseed)
|
||||
build_a_village(minp, maxp, chunkkseed)
|
||||
end, mcl_mapgen.order.VILLAGES)
|
||||
end
|
||||
-- manually place villages
|
||||
if minetest.is_creative_enabled("") then
|
||||
minetest.register_craftitem("mcl_villages:tool", {
|
||||
description = "mcl_villages build tool",
|
||||
inventory_image = "default_tool_woodshovel.png",
|
||||
-- build ssettlement
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
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(minp, maxp, math.random(0,32767))
|
||||
|
||||
for k, v in pairs(schematic_table) do
|
||||
local schem_lua = minetest.serialize_schematic(
|
||||
v.mts,
|
||||
"lua",
|
||||
{
|
||||
lua_use_comments = false,
|
||||
lua_num_indent_spaces = 0,
|
||||
}
|
||||
):gsub("mcl_core:stonebrickcarved", "mcl_villages:stonebrickcarved") .. " return schematic"
|
||||
v.preloaded_schematic = schem_lua
|
||||
local loaded_schematic = loadstring(schem_lua)()
|
||||
local size = loaded_schematic.size
|
||||
v.hwidth = size.x
|
||||
v.hheight = size.y
|
||||
v.hdepth = size.z
|
||||
v.hsize = math.ceil(math.sqrt((size.x/2)^2 + (size.y/2)^2) * 2 + 1)
|
||||
mcl_structures.register_structure({
|
||||
name = v.name,
|
||||
place_function = function(pos, rotation, pr, placer)
|
||||
local minp = mcl_mapgen.get_chunk_beginning(pos)
|
||||
local maxp = mcl_mapgen.get_chunk_ending(pos)
|
||||
local surface_pos, surface_material = find_surface(pos, minp, maxp)
|
||||
local plan = {
|
||||
[1] = {
|
||||
pos = pos,
|
||||
building = schematic_table[k],
|
||||
rotation = rotation,
|
||||
surface_mat = surface_material or "mcl_core:snow",
|
||||
}
|
||||
}
|
||||
if surface_material then
|
||||
terraform(plan, minp, maxp, pr)
|
||||
end
|
||||
place_schematics(plan, pr)
|
||||
end
|
||||
})
|
||||
mcl_wip.register_experimental_item("mcl_villages:tool")
|
||||
end
|
||||
|
||||
mcl_structures.register_structure({
|
||||
name = "village",
|
||||
place_function = function(pos, rotation, pr, placer)
|
||||
local minp = mcl_mapgen.get_chunk_beginning(pos)
|
||||
local maxp = mcl_mapgen.get_chunk_ending(pos)
|
||||
build_a_village(minp, maxp, pr, placer)
|
||||
end
|
||||
})
|
||||
|
||||
function mcl_villages.get_villages()
|
||||
return villages
|
||||
end
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# textdomain: mcl_villages
|
||||
Chiseled Stone Village Bricks=Точёный каменный блок из деревни
|
||||
Map chunk @1 to @2 is not suitable for placing villages.=Чанк с @1 по @2 непригоден для размещения деревень.
|
|
@ -0,0 +1,3 @@
|
|||
# textdomain: mcl_villages
|
||||
Chiseled Stone Village Bricks=
|
||||
Map chunk @1 to @2 is not suitable for placing villages.=
|
|
@ -1,5 +1,5 @@
|
|||
name = mcl_villages
|
||||
author = Rochambeau
|
||||
description = This mod adds settlements on world generation.
|
||||
depends = mcl_util, mcl_mapgen_core, mcl_structures, mcl_core, mcl_loot
|
||||
author = Rochambeau, MysticTempest, kay27
|
||||
description = This mod adds villages on world generation.
|
||||
depends = mcl_util, mcl_structures, mcl_core, mcl_loot, mcl_mapgen
|
||||
optional_depends = mcl_farming, mobs_mc
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- generate paths between buildings
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.paths(settlement_info)
|
||||
local starting_point
|
||||
local end_point
|
||||
local distance
|
||||
--for k,v in pairs(settlement_info) do
|
||||
starting_point = settlement_info[1]["pos"]
|
||||
for o,p in pairs(settlement_info) do
|
||||
|
||||
end_point = settlement_info[o]["pos"]
|
||||
if starting_point ~= end_point
|
||||
then
|
||||
-- loop until end_point is reched (distance == 0)
|
||||
while true do
|
||||
|
||||
-- define surrounding pos to starting_point
|
||||
local north_p = {x=starting_point.x+1, y=starting_point.y, z=starting_point.z}
|
||||
local south_p = {x=starting_point.x-1, y=starting_point.y, z=starting_point.z}
|
||||
local west_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z+1}
|
||||
local east_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z-1}
|
||||
-- measure distance to end_point
|
||||
local dist_north_p_to_end = math.sqrt(
|
||||
((north_p.x - end_point.x)*(north_p.x - end_point.x))+
|
||||
((north_p.z - end_point.z)*(north_p.z - end_point.z))
|
||||
)
|
||||
local dist_south_p_to_end = math.sqrt(
|
||||
((south_p.x - end_point.x)*(south_p.x - end_point.x))+
|
||||
((south_p.z - end_point.z)*(south_p.z - end_point.z))
|
||||
)
|
||||
local dist_west_p_to_end = math.sqrt(
|
||||
((west_p.x - end_point.x)*(west_p.x - end_point.x))+
|
||||
((west_p.z - end_point.z)*(west_p.z - end_point.z))
|
||||
)
|
||||
local dist_east_p_to_end = math.sqrt(
|
||||
((east_p.x - end_point.x)*(east_p.x - end_point.x))+
|
||||
((east_p.z - end_point.z)*(east_p.z - end_point.z))
|
||||
)
|
||||
-- evaluate which pos is closer to the end_point
|
||||
if dist_north_p_to_end <= dist_south_p_to_end and
|
||||
dist_north_p_to_end <= dist_west_p_to_end and
|
||||
dist_north_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = north_p
|
||||
distance = dist_north_p_to_end
|
||||
|
||||
elseif dist_south_p_to_end <= dist_north_p_to_end and
|
||||
dist_south_p_to_end <= dist_west_p_to_end and
|
||||
dist_south_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = south_p
|
||||
distance = dist_south_p_to_end
|
||||
|
||||
elseif dist_west_p_to_end <= dist_north_p_to_end and
|
||||
dist_west_p_to_end <= dist_south_p_to_end and
|
||||
dist_west_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = west_p
|
||||
distance = dist_west_p_to_end
|
||||
|
||||
elseif dist_east_p_to_end <= dist_north_p_to_end and
|
||||
dist_east_p_to_end <= dist_south_p_to_end and
|
||||
dist_east_p_to_end <= dist_west_p_to_end
|
||||
then
|
||||
starting_point = east_p
|
||||
distance = dist_east_p_to_end
|
||||
end
|
||||
-- find surface of new starting point
|
||||
local surface_point, surface_mat = settlements.find_surface(starting_point)
|
||||
-- replace surface node with mcl_core:grass_path
|
||||
if surface_point
|
||||
then
|
||||
if surface_mat == "mcl_core:sand" or surface_mat == "mcl_core:redsand" then
|
||||
minetest.swap_node(surface_point,{name="mcl_core:sandstonesmooth2"})
|
||||
else
|
||||
minetest.swap_node(surface_point,{name="mcl_core:grass_path"})
|
||||
end
|
||||
-- don't set y coordinate, surface might be too low or high
|
||||
starting_point.x = surface_point.x
|
||||
starting_point.z = surface_point.z
|
||||
end
|
||||
if distance <= 1 or
|
||||
starting_point == end_point
|
||||
then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,217 +0,0 @@
|
|||
local get_node = mcl_mapgen.get_far_node
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to copy tables
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.shallowCopy(original)
|
||||
local copy = {}
|
||||
for key, value in pairs(original) do
|
||||
copy[key] = value
|
||||
end
|
||||
return copy
|
||||
end
|
||||
--
|
||||
--
|
||||
--
|
||||
function settlements.round(num, numDecimalPlaces)
|
||||
local mult = 10^(numDecimalPlaces or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to find surface block y coordinate
|
||||
-- returns surface postion
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.find_surface(pos, wait)
|
||||
local p6 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local itter = 1 -- count up or down
|
||||
local cnt_max = 200
|
||||
-- check, in which direction to look for surface
|
||||
local surface_node
|
||||
if wait then
|
||||
surface_node = get_node(p6, true, 10000000)
|
||||
else
|
||||
surface_node = 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
|
||||
-- Check Surface_node and Node above
|
||||
--
|
||||
if settlements.surface_mat[surface_node.name] then
|
||||
local surface_node_plus_1 = 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
|
||||
string.find(surface_node_plus_1.name,"fern") or
|
||||
string.find(surface_node_plus_1.name,"flower") or
|
||||
string.find(surface_node_plus_1.name,"bush") or
|
||||
string.find(surface_node_plus_1.name,"tree") or
|
||||
string.find(surface_node_plus_1.name,"grass"))
|
||||
then
|
||||
settlements.debug("find_surface7: " ..surface_node.name.. " " .. surface_node_plus_1.name)
|
||||
return p6, surface_node.name
|
||||
else
|
||||
settlements.debug("find_surface2: wrong surface+1")
|
||||
end
|
||||
else
|
||||
settlements.debug("find_surface3: wrong surface "..surface_node.name.." at pos "..minetest.pos_to_string(p6))
|
||||
end
|
||||
|
||||
p6.y = p6.y + itter
|
||||
if p6.y < 0 then
|
||||
settlements.debug("find_surface4: y<0")
|
||||
return nil
|
||||
end
|
||||
cnt = cnt+1
|
||||
surface_node = get_node(p6)
|
||||
end
|
||||
settlements.debug("find_surface5: cnt_max overflow")
|
||||
return nil
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- check distance for new building
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.check_distance(settlement_info, building_pos, building_size)
|
||||
local distance
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
distance = math.sqrt(
|
||||
((building_pos.x - built_house["pos"].x)*(building_pos.x - built_house["pos"].x))+
|
||||
((building_pos.z - built_house["pos"].z)*(building_pos.z - built_house["pos"].z)))
|
||||
if distance < building_size or distance < built_house["hsize"] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- save list of generated settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.save()
|
||||
local file = io.open(minetest.get_worldpath().."/settlements.txt", "w")
|
||||
if file then
|
||||
file:write(minetest.serialize(settlements_in_world))
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- load list of generated settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.load()
|
||||
local file = io.open(minetest.get_worldpath().."/settlements.txt", "r")
|
||||
if file then
|
||||
local table = minetest.deserialize(file:read("*all"))
|
||||
if type(table) == "table" then
|
||||
return table
|
||||
end
|
||||
end
|
||||
return {}
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- fill chests
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.fill_chest(pos, pr)
|
||||
-- initialize chest (mts chests don't have meta)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if meta:get_string("infotext") ~= "Chest" then
|
||||
-- For MineClone2 0.70 or before
|
||||
-- minetest.registered_nodes["mcl_chests:chest"].on_construct(pos)
|
||||
--
|
||||
-- For MineClone2 after commit 09ab1482b5 (the new entity chests)
|
||||
minetest.registered_nodes["mcl_chests:chest_small"].on_construct(pos)
|
||||
end
|
||||
-- fill chest
|
||||
local inv = minetest.get_inventory( {type="node", pos=pos} )
|
||||
|
||||
local function get_treasures(prand)
|
||||
local loottable = {{
|
||||
stacks_min = 3,
|
||||
stacks_max = 8,
|
||||
items = {
|
||||
{ itemstring = "mcl_core:diamond", weight = 3, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:iron_ingot", weight = 10, amount_min = 1, amount_max = 5 },
|
||||
{ itemstring = "mcl_core:gold_ingot", weight = 5, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_farming:bread", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_core:apple", weight = 15, amount_min = 1, amount_max = 3 },
|
||||
{ itemstring = "mcl_tools:pick_iron", weight = 5 },
|
||||
{ itemstring = "mcl_tools:sword_iron", weight = 5 },
|
||||
{ itemstring = "mcl_armor:chestplate_iron", weight = 5 },
|
||||
{ itemstring = "mcl_armor:helmet_iron", weight = 5 },
|
||||
{ itemstring = "mcl_armor:leggings_iron", weight = 5 },
|
||||
{ itemstring = "mcl_armor:boots_iron", weight = 5 },
|
||||
{ itemstring = "mcl_core:obsidian", weight = 5, amount_min = 3, amount_max = 7 },
|
||||
{ itemstring = "mcl_core:sapling", weight = 5, amount_min = 3, amount_max = 7 },
|
||||
{ itemstring = "mcl_mobitems:saddle", weight = 3 },
|
||||
{ itemstring = "mobs_mc:iron_horse_armor", weight = 1 },
|
||||
{ itemstring = "mobs_mc:gold_horse_armor", weight = 1 },
|
||||
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 1 },
|
||||
}
|
||||
}}
|
||||
local items = mcl_loot.get_multi_loot(loottable, prand)
|
||||
return items
|
||||
end
|
||||
|
||||
local items = get_treasures(pr)
|
||||
mcl_loot.fill_inventory(inv, "main", items, pr)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize furnace
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_furnace(pos)
|
||||
-- find chests within radius
|
||||
local furnacepos = minetest.find_node_near(pos,
|
||||
7, --radius
|
||||
{"mcl_furnaces:furnace"})
|
||||
-- initialize furnacepos (mts furnacepos don't have meta)
|
||||
if furnacepos
|
||||
then
|
||||
local meta = minetest.get_meta(furnacepos)
|
||||
if meta:get_string("infotext") ~= "furnace"
|
||||
then
|
||||
minetest.registered_nodes["mcl_furnaces:furnace"].on_construct(furnacepos)
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize anvil
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_anvil(pos)
|
||||
-- find chests within radius
|
||||
local anvilpos = minetest.find_node_near(pos,
|
||||
7, --radius
|
||||
{"mcl_anvils:anvil"})
|
||||
-- initialize anvilpos (mts anvilpos don't have meta)
|
||||
if anvilpos
|
||||
then
|
||||
local meta = minetest.get_meta(anvilpos)
|
||||
if meta:get_string("infotext") ~= "anvil"
|
||||
then
|
||||
minetest.registered_nodes["mcl_anvils:anvil"].on_construct(anvilpos)
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- randomize table
|
||||
-------------------------------------------------------------------------------
|
||||
function shuffle(tbl, pr)
|
||||
local table = settlements.shallowCopy(tbl)
|
||||
local size = #table
|
||||
for i = size, 1, -1 do
|
||||
local rand = pr:next(1, size)
|
||||
table[i], table[rand] = table[rand], table[i]
|
||||
end
|
||||
return table
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.Set (list)
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
end
|
Loading…
Reference in New Issue