From 54ea8ba6b1066d9fcd4bdfd6e25e07d099a0f796 Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 18 Feb 2022 03:48:03 +0400 Subject: [PATCH] Update mapgen api to v3 from mcl5 --- mods/CORE/mcl_mapgen/init.lua | 369 ++++++----- mods/CORE/mcl_time/README.md | 52 ++ mods/CORE/mcl_time/init.lua | 140 +++++ mods/CORE/mcl_time/mod.conf | 3 + mods/ITEMS/mcl_nether/nether_wart.lua | 61 +- mods/MAPGEN/mcl_mapgen_core/biomes.lua | 50 ++ mods/MAPGEN/mcl_mapgen_core/init.lua | 465 ++------------ mods/MAPGEN/mcl_mapgen_core/light.lua | 41 ++ mods/MAPGEN/mcl_mapgen_core/nether.lua | 131 ++++ mods/MAPGEN/mcl_mapgen_core/nether_wart.lua | 57 ++ mods/MAPGEN/mcl_mapgen_core/v6.lua | 49 ++ mods/MAPGEN/mcl_ocean_monument/init.lua | 15 +- mods/MAPGEN/mcl_structures/desert_temple.lua | 8 +- mods/MAPGEN/mcl_structures/desert_well.lua | 6 +- .../MAPGEN/mcl_structures/end_exit_portal.lua | 29 + mods/MAPGEN/mcl_structures/fossil.lua | 2 +- .../MAPGEN/mcl_structures/ice_spike_small.lua | 2 +- mods/MAPGEN/mcl_structures/igloo.lua | 7 +- mods/MAPGEN/mcl_structures/init.lua | 25 +- mods/MAPGEN/mcl_structures/jungle_temple.lua | 7 +- .../mcl_structures/nice_jungle_temple.lua | 7 +- .../MAPGEN/mcl_structures/noise_indicator.lua | 2 +- mods/MAPGEN/mcl_structures/witch_hut.lua | 8 +- mods/MAPGEN/mcl_villages/README.md | 22 + mods/MAPGEN/mcl_villages/README.txt | 45 -- mods/MAPGEN/mcl_villages/buildings.lua | 224 ------- mods/MAPGEN/mcl_villages/const.lua | 81 --- mods/MAPGEN/mcl_villages/foundation.lua | 59 -- mods/MAPGEN/mcl_villages/init.lua | 576 +++++++++++++++--- .../mcl_villages/locale/mcl_villages.ru.tr | 3 + mods/MAPGEN/mcl_villages/locale/template.txt | 3 + mods/MAPGEN/mcl_villages/mod.conf | 6 +- mods/MAPGEN/mcl_villages/paths.lua | 91 --- .../mcl_villages/schematics/blacksmith.mts | Bin 986 -> 1052 bytes .../mcl_villages/schematics/butcher.mts | Bin 813 -> 919 bytes .../MAPGEN/mcl_villages/schematics/church.mts | Bin 956 -> 1128 bytes mods/MAPGEN/mcl_villages/schematics/farm.mts | Bin 347 -> 324 bytes mods/MAPGEN/mcl_villages/schematics/lamp.mts | Bin 209 -> 170 bytes .../mcl_villages/schematics/large_house.mts | Bin 1137 -> 1271 bytes .../mcl_villages/schematics/library.mts | Bin 816 -> 892 bytes .../mcl_villages/schematics/medium_house.mts | Bin 760 -> 830 bytes .../mcl_villages/schematics/small_house.mts | Bin 593 -> 617 bytes .../MAPGEN/mcl_villages/schematics/tavern.mts | Bin 1005 -> 1138 bytes mods/MAPGEN/mcl_villages/schematics/well.mts | Bin 476 -> 456 bytes mods/MAPGEN/mcl_villages/utils.lua | 217 ------- 45 files changed, 1423 insertions(+), 1440 deletions(-) create mode 100644 mods/CORE/mcl_time/README.md create mode 100644 mods/CORE/mcl_time/init.lua create mode 100644 mods/CORE/mcl_time/mod.conf create mode 100644 mods/MAPGEN/mcl_mapgen_core/biomes.lua create mode 100644 mods/MAPGEN/mcl_mapgen_core/light.lua create mode 100644 mods/MAPGEN/mcl_mapgen_core/nether.lua create mode 100644 mods/MAPGEN/mcl_mapgen_core/nether_wart.lua create mode 100644 mods/MAPGEN/mcl_mapgen_core/v6.lua create mode 100644 mods/MAPGEN/mcl_villages/README.md delete mode 100644 mods/MAPGEN/mcl_villages/README.txt delete mode 100644 mods/MAPGEN/mcl_villages/buildings.lua delete mode 100644 mods/MAPGEN/mcl_villages/const.lua delete mode 100644 mods/MAPGEN/mcl_villages/foundation.lua create mode 100644 mods/MAPGEN/mcl_villages/locale/mcl_villages.ru.tr create mode 100644 mods/MAPGEN/mcl_villages/locale/template.txt delete mode 100644 mods/MAPGEN/mcl_villages/paths.lua delete mode 100644 mods/MAPGEN/mcl_villages/utils.lua diff --git a/mods/CORE/mcl_mapgen/init.lua b/mods/CORE/mcl_mapgen/init.lua index db79e59f7..f24d76880 100644 --- a/mods/CORE/mcl_mapgen/init.lua +++ b/mods/CORE/mcl_mapgen/init.lua @@ -19,13 +19,21 @@ local minetest_log = minetest.log local minetest_pos_to_string = minetest.pos_to_string -- Calculate mapgen_edge_min/mapgen_edge_max -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.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.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 = 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 = {} @@ -76,12 +85,16 @@ local nodes_block = 0 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 BS, CS = mcl_mapgen.BS, mcl_mapgen.CS -- Mapblock size (in nodes), Mapchunk size (in blocks) +local offset = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks) +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} - 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 + 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[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 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} - 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 } - end - else - blocks[bx][by][bz] = current_mapgen_block_writes end - z = z + BS 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 + 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 + if nodes_block > 0 then + current_blocks[#current_blocks + 1] = { minp = block_minp, maxp = block_maxp, blockseed = blockseed } + end + end + number_of_blocks = number_of_blocks + 1 + end + 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,14 +443,12 @@ 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 - nether.flat_floor = nether.lava_max + 4 - nether.flat_ceiling = nether.lava_max + 52 - end +if superflat then + nether.flat_floor = nether.bedrock_bottom_max + 4 + nether.flat_ceiling = nether.bedrock_bottom_max + 52 +elseif flat then + nether.flat_floor = nether.lava_max + 4 + nether.flat_ceiling = nether.lava_max + 52 end -- The End (surface at ca. Y = -27000) @@ -498,5 +505,31 @@ function mcl_mapgen.clamp_to_chunk(x, size) end function mcl_mapgen.get_chunk_beginning(x) - return x - ((x + central_chunk_min_pos) % CS_NODES) + 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 diff --git a/mods/CORE/mcl_time/README.md b/mods/CORE/mcl_time/README.md new file mode 100644 index 000000000..c3a1bb3af --- /dev/null +++ b/mods/CORE/mcl_time/README.md @@ -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. diff --git a/mods/CORE/mcl_time/init.lua b/mods/CORE/mcl_time/init.lua new file mode 100644 index 000000000..31bcbbe29 --- /dev/null +++ b/mods/CORE/mcl_time/init.lua @@ -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) +) diff --git a/mods/CORE/mcl_time/mod.conf b/mods/CORE/mcl_time/mod.conf new file mode 100644 index 000000000..c1f6f0948 --- /dev/null +++ b/mods/CORE/mcl_time/mod.conf @@ -0,0 +1,3 @@ +name = mcl_time +author = kay27 +description = This mod counts time when all players sleep or some area is inactive diff --git a/mods/ITEMS/mcl_nether/nether_wart.lua b/mods/ITEMS/mcl_nether/nether_wart.lua index 41b23f662..0fe1a990a 100644 --- a/mods/ITEMS/mcl_nether/nether_wart.lua +++ b/mods/ITEMS/mcl_nether/nether_wart.lua @@ -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,40 +152,65 @@ 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"} +local function grow(pos, node) + local step = nil + for i, name in ipairs(names) do + if name == node.name then + step = i + break + end + end + if not step then return end + local new_node = {name = names[step + 1]} + 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 = 35, - chance = 11, + 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 - local step = nil - for i,name in ipairs(names) do - if name == node.name then - step = i - break - end + + for i = 1, mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance) do + grow(pos, node) end - if step == nil then + 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 - local new_node = {name=names[step+1]} - if new_node.name == nil then - new_node.name = "mcl_nether:nether_wart" + pos.y = pos.y+1 + for i = 1, mcl_time.get_number_of_times_at_pos(pos, interval, chance) do + grow(pos, node) end - new_node.param = node.param - new_node.param2 = node.param2 - minetest.set_node(pos, new_node) end }) if minetest.get_modpath("doc") then - for i=1,2 do + for i=1, 2 do doc.add_entry_alias("nodes", "mcl_nether:nether_wart_0", "nodes", "mcl_nether:nether_wart_"..i) end end diff --git a/mods/MAPGEN/mcl_mapgen_core/biomes.lua b/mods/MAPGEN/mcl_mapgen_core/biomes.lua new file mode 100644 index 000000000..d50f4da56 --- /dev/null +++ b/mods/MAPGEN/mcl_mapgen_core/biomes.lua @@ -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) diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 8f4278357..e628321f0 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -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) - - + 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 - -- 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) - end - -- 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 - 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 + set_layers(vm_context, pr, mcl_mapgen.nether.min, mcl_mapgen.nether.lava_max, c_nether.lava, c_air) 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 diff --git a/mods/MAPGEN/mcl_mapgen_core/light.lua b/mods/MAPGEN/mcl_mapgen_core/light.lua new file mode 100644 index 000000000..a0b503352 --- /dev/null +++ b/mods/MAPGEN/mcl_mapgen_core/light.lua @@ -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) diff --git a/mods/MAPGEN/mcl_mapgen_core/nether.lua b/mods/MAPGEN/mcl_mapgen_core/nether.lua new file mode 100644 index 000000000..1b05d32bf --- /dev/null +++ b/mods/MAPGEN/mcl_mapgen_core/nether.lua @@ -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) diff --git a/mods/MAPGEN/mcl_mapgen_core/nether_wart.lua b/mods/MAPGEN/mcl_mapgen_core/nether_wart.lua new file mode 100644 index 000000000..7ea73ca4b --- /dev/null +++ b/mods/MAPGEN/mcl_mapgen_core/nether_wart.lua @@ -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) diff --git a/mods/MAPGEN/mcl_mapgen_core/v6.lua b/mods/MAPGEN/mcl_mapgen_core/v6.lua new file mode 100644 index 000000000..19fd44647 --- /dev/null +++ b/mods/MAPGEN/mcl_mapgen_core/v6.lua @@ -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) diff --git a/mods/MAPGEN/mcl_ocean_monument/init.lua b/mods/MAPGEN/mcl_ocean_monument/init.lua index fffa6f6b0..94f70643b 100644 --- a/mods/MAPGEN/mcl_ocean_monument/init.lua +++ b/mods/MAPGEN/mcl_ocean_monument/init.lua @@ -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 diff --git a/mods/MAPGEN/mcl_structures/desert_temple.lua b/mods/MAPGEN/mcl_structures/desert_temple.lua index bb4c08b3a..e35880ab2 100644 --- a/mods/MAPGEN/mcl_structures/desert_temple.lua +++ b/mods/MAPGEN/mcl_structures/desert_temple.lua @@ -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 { diff --git a/mods/MAPGEN/mcl_structures/desert_well.lua b/mods/MAPGEN/mcl_structures/desert_well.lua index af57c8183..83ab3f14f 100644 --- a/mods/MAPGEN/mcl_structures/desert_well.lua +++ b/mods/MAPGEN/mcl_structures/desert_well.lua @@ -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 diff --git a/mods/MAPGEN/mcl_structures/end_exit_portal.lua b/mods/MAPGEN/mcl_structures/end_exit_portal.lua index a0a171ee7..3eeaf7819 100644 --- a/mods/MAPGEN/mcl_structures/end_exit_portal.lua +++ b/mods/MAPGEN/mcl_structures/end_exit_portal.lua @@ -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 diff --git a/mods/MAPGEN/mcl_structures/fossil.lua b/mods/MAPGEN/mcl_structures/fossil.lua index b26b7320a..6c6c2d24b 100644 --- a/mods/MAPGEN/mcl_structures/fossil.lua +++ b/mods/MAPGEN/mcl_structures/fossil.lua @@ -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) diff --git a/mods/MAPGEN/mcl_structures/ice_spike_small.lua b/mods/MAPGEN/mcl_structures/ice_spike_small.lua index 801c5f66e..387c61bab 100644 --- a/mods/MAPGEN/mcl_structures/ice_spike_small.lua +++ b/mods/MAPGEN/mcl_structures/ice_spike_small.lua @@ -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, diff --git a/mods/MAPGEN/mcl_structures/igloo.lua b/mods/MAPGEN/mcl_structures/igloo.lua index 4f6c9574f..42f434a9a 100644 --- a/mods/MAPGEN/mcl_structures/igloo.lua +++ b/mods/MAPGEN/mcl_structures/igloo.lua @@ -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 diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 64f6db937..83646179b 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -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) diff --git a/mods/MAPGEN/mcl_structures/jungle_temple.lua b/mods/MAPGEN/mcl_structures/jungle_temple.lua index 635f35670..f6edd9891 100644 --- a/mods/MAPGEN/mcl_structures/jungle_temple.lua +++ b/mods/MAPGEN/mcl_structures/jungle_temple.lua @@ -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 diff --git a/mods/MAPGEN/mcl_structures/nice_jungle_temple.lua b/mods/MAPGEN/mcl_structures/nice_jungle_temple.lua index dd8df05d3..a301d491b 100644 --- a/mods/MAPGEN/mcl_structures/nice_jungle_temple.lua +++ b/mods/MAPGEN/mcl_structures/nice_jungle_temple.lua @@ -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 diff --git a/mods/MAPGEN/mcl_structures/noise_indicator.lua b/mods/MAPGEN/mcl_structures/noise_indicator.lua index 7cc130358..0a3038bb2 100644 --- a/mods/MAPGEN/mcl_structures/noise_indicator.lua +++ b/mods/MAPGEN/mcl_structures/noise_indicator.lua @@ -57,4 +57,4 @@ mcl_mapgen.register_mapgen(function(minp, maxp, seed, vm_context) end end end -end, -1) +end, 99999999999999) diff --git a/mods/MAPGEN/mcl_structures/witch_hut.lua b/mods/MAPGEN/mcl_structures/witch_hut.lua index f6dc6ec9b..72b3c4852 100644 --- a/mods/MAPGEN/mcl_structures/witch_hut.lua +++ b/mods/MAPGEN/mcl_structures/witch_hut.lua @@ -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 diff --git a/mods/MAPGEN/mcl_villages/README.md b/mods/MAPGEN/mcl_villages/README.md new file mode 100644 index 000000000..3d1531fb3 --- /dev/null +++ b/mods/MAPGEN/mcl_villages/README.md @@ -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 diff --git a/mods/MAPGEN/mcl_villages/README.txt b/mods/MAPGEN/mcl_villages/README.txt deleted file mode 100644 index f669f2051..000000000 --- a/mods/MAPGEN/mcl_villages/README.txt +++ /dev/null @@ -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 - diff --git a/mods/MAPGEN/mcl_villages/buildings.lua b/mods/MAPGEN/mcl_villages/buildings.lua deleted file mode 100644 index c5cebf9fe..000000000 --- a/mods/MAPGEN/mcl_villages/buildings.lua +++ /dev/null @@ -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 diff --git a/mods/MAPGEN/mcl_villages/const.lua b/mods/MAPGEN/mcl_villages/const.lua deleted file mode 100644 index eb7806209..000000000 --- a/mods/MAPGEN/mcl_villages/const.lua +++ /dev/null @@ -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 diff --git a/mods/MAPGEN/mcl_villages/foundation.lua b/mods/MAPGEN/mcl_villages/foundation.lua deleted file mode 100644 index ed489f901..000000000 --- a/mods/MAPGEN/mcl_villages/foundation.lua +++ /dev/null @@ -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 diff --git a/mods/MAPGEN/mcl_villages/init.lua b/mods/MAPGEN/mcl_villages/init.lua index 47ca91f2e..fcd54174d 100644 --- a/mods/MAPGEN/mcl_villages/init.lua +++ b/mods/MAPGEN/mcl_villages/init.lua @@ -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 -local minetest_get_spawn_level = minetest.get_spawn_level +local function math_round(x) + return (x < 0) and math_ceil(x - 0.5) or math_floor(x + 0.5) +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 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 diff --git a/mods/MAPGEN/mcl_villages/locale/mcl_villages.ru.tr b/mods/MAPGEN/mcl_villages/locale/mcl_villages.ru.tr new file mode 100644 index 000000000..325d3b191 --- /dev/null +++ b/mods/MAPGEN/mcl_villages/locale/mcl_villages.ru.tr @@ -0,0 +1,3 @@ +# textdomain: mcl_villages +Chiseled Stone Village Bricks=Точёный каменный блок из деревни +Map chunk @1 to @2 is not suitable for placing villages.=Чанк с @1 по @2 непригоден для размещения деревень. \ No newline at end of file diff --git a/mods/MAPGEN/mcl_villages/locale/template.txt b/mods/MAPGEN/mcl_villages/locale/template.txt new file mode 100644 index 000000000..7d9fcb43b --- /dev/null +++ b/mods/MAPGEN/mcl_villages/locale/template.txt @@ -0,0 +1,3 @@ +# textdomain: mcl_villages +Chiseled Stone Village Bricks= +Map chunk @1 to @2 is not suitable for placing villages.= diff --git a/mods/MAPGEN/mcl_villages/mod.conf b/mods/MAPGEN/mcl_villages/mod.conf index d8e2aa7d4..eb4a5d080 100644 --- a/mods/MAPGEN/mcl_villages/mod.conf +++ b/mods/MAPGEN/mcl_villages/mod.conf @@ -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 diff --git a/mods/MAPGEN/mcl_villages/paths.lua b/mods/MAPGEN/mcl_villages/paths.lua deleted file mode 100644 index 63f2ba146..000000000 --- a/mods/MAPGEN/mcl_villages/paths.lua +++ /dev/null @@ -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 diff --git a/mods/MAPGEN/mcl_villages/schematics/blacksmith.mts b/mods/MAPGEN/mcl_villages/schematics/blacksmith.mts index d7fb66593dba1636ba133681520ae16721d276b8..09665654a91c13f5ea5f484159ad650954885192 100644 GIT binary patch delta 576 zcmcb`K8HigHze4XfrWvcfsKK)9t;>{7?=|?ix~KGlXK#e^NUiglJk?2a#ANpFquvc zVw9dZRi0k}B$t+&mz-K`1*9e~V3MBvmQhYy1geNl|L*&jGXhNnM zGqZS?rh@U(2W16@56aa&rnNSI{b znVDI5(s{`PIUO>>H*7j=ww_I4xz)8n{84n-g7c0G86R>QcNi#qcDeY7U4^|+{mT2V zEsQ1{1sZ?;|F@4}^HmLb_P@SEYSoIC+pRfLE&}_l6DQ8)58-@bbmj2ZMhSs~RT`~I z?z_Ae7=9ISo~W7fTf%@*nA!0_%PO|{d~R%M8wz`PjxePqxTP*oJMhY8LiL0@N6z%5 iC@VKxaPd!Re88lkHPbM}$UsoA&cXEz55xPgm3sjLWZZfH delta 531 zcmbQkaf`j)Hze4XfrWvcfrEj&9ts%b7$kC&bK;Zpi&CvpGK)&$%QH(d;?s)~i;EeU z6Elk#cu}Mo_~G2-{G_CuR3!P5qSRCd5x9I(QD$;>d{Rz+ayElRMM2_ZM<%g}Rq_f5 z1IzRCQy2t58q!kpl2ePVz|`b^MpH)p$q`JtQfX-nVj$^~{G#Lxpgfq4FHg+LnHVQC zS&2z}ax|kFkd~gz%c#L9GciGoH6_0^DQEIWM#IVTndF!l#3wIc5})WSGx4FAIM^tV z=3=YjlKi|>hyyJrA7<3AubA^Te@%Q6*3pO9x zRHVVca`8z@%bWt%jn0dOQr>(Gygy^lmW5x|UhUv1y76F6RPNQQ8Yh)J;%+_je3lh^ zZK_4>MV87ESF80Llhk)QFU$J>&0@MtX@GTEPRNrt@f|jYea@CP8BeJ=f8|FJS7qkZ ze__8qX9?W+W1~>X;ofAHH^7AZ>?e8b|^Z)qs Q>U;CXzI>f~-O^UC0EnC4S^xk5 diff --git a/mods/MAPGEN/mcl_villages/schematics/butcher.mts b/mods/MAPGEN/mcl_villages/schematics/butcher.mts index 251033b1ec0a3e7bf299f833ab1ffd90e35c18b3..03353de105ded131339bf1d97b4c8dafc59d077b 100644 GIT binary patch delta 589 zcmZ3>Hl5wgHze4XfrWvafrEjq9ts%57?=|?ix~KGlXK#e^NUiglJk?2a#9&2-~uU` zMJ4g&nI#$V=|zdf#giv7nof*RocxGUTr4Tx5J_iFVoFMC5rfR+ct%mq_>}xokU63g z?~6{X&;u%$mXQRRnOTyWn^u&Vn_6rIV#b5n40@A=8FeM|7{owIO7e@6Gl247I=(zH zCui~>M#YKy6ehJQ(qC6oN$CmQX=Bvgo%y3Jd%Thi z;pu}7y0!%d6XwYo6yH%em;bfkK*JdpSM?d^8PcyB8!YHDQV=m{xS`?6d~?HphlVBF z#DhVLBZwiji+O6NP^Ml4cZmFoIn5c$H)GOvlyZnM3r%KxBq#HX zsrBP7@fYS|D_9fM?j+362xwpxeaPiS8y7=SWZ1Vw9e|f>EI!VP8&SN=j-`#hkaH z-9k+Y0yZs1@)x;Z7XSV_!Mx+DM%d#D>nd~Ydz%g^I2c{f3Q%Ea5O#3TF?gd=RhD1< zHD_gHv$Mgqg-ub5xNfjTb*jx;np9kAELdfn|2E}r*PHKJ4_C|&>VJDYV6JSIh3A!t z?FRdkCe977&&z+l#Qd|#7q_Lm|9>f)_&xi9@6+fDr#I-FRC=LSy|}wldfn_#M;32Q znAZFKNx_;=$0pzVap?87w#_L=|2G^Li_ZDDRl?G{PW0lWsy8T1b1(5WRs2oCXwYO78Pw{Y+rY8Z)`euXlZn1Ut?i%aAkCnkSCK} z0T`3P0WgubB$FZn7LyW%zLFAuNMo4FmN;lo=Sdvx3pQDl2qP(l=0h6Buj`G*I?al8aW2QzQu4maF?GGaKx zS`4QP7;)->rE5qi!s-kNZ!|=yAEKkV9+DJs*K?%idXRd2Z6xHnezazSgznI2Jqe&B z1;Jt5dcxfb7;WJ*;;GRY=m17iFO<~atgnaZK(J^ZCG~Isw2L@SeLb=|;tgPc*nr<2 zco-1v9ESS;AOLa)NY8&LsK?-cK-B#Qhi*Lz2SpEx3vimoKtqS(_5u|hiW-XysL@Dd zh!W>e2FgN|M28Yi2Smmx$x%OC9SRJHdi*(yRw2s3fTwh!Y8tH{_*_5m#S^ZoU|hnt=h` z=TvhjioxV0YBp4VQW9a0)-C6?HqDs@TDClv?)HSMLlkZ5}B0Q@T-G3 llxbjQDDh<`bY~Bl;)$qu84LwJQ4U3<3?{nOOaRhvcavh^&eZ`!&5uIht z3IZ+}HnYq!XUEmwj$be2yJK4P!Rd1=EfeN#*q!X)#L>aFQ!=}tQE1uMjT^U@QT;w4`^@JRS7WLkyn0gB zI5GX7)w!4{ezPAhsA6uQE1VQrECLz3YJ6x~EO`t`D=5 z+={KYw{lMjzjnOUc=^dz^K*Oj4xHK@d~xQZIk#I=@0RXP_>@r8*t@wl!e(!QoT>Pe z3RiKLxFtUJrhm1w*Csx_z4E}n8J|RB1-{#tB=YM$=n}CyFQqN??%YDJwdXyu?N;{+ycaaNXT z0wLCW&%TW8$x@b5^zc-aEYw_a_0%*cW-}YXxlRfX93*de_?;7Tws_!>ELFH5q*wED q?-ZGgN9QAbbCjpVPt=MG*&Fcv+OyW*wQk>MITf<~VfL&|?*;&du=@`H diff --git a/mods/MAPGEN/mcl_villages/schematics/farm.mts b/mods/MAPGEN/mcl_villages/schematics/farm.mts index 9094c8681fcde6d5c441593224154176330b7372..e47f6e22f4dd4875a5b3abe920b08e9fa23f7bf8 100644 GIT binary patch delta 214 zcmcc3bc9L7Hze4XfrWvcfsKK^9t;>bC)$fntkmTf$W6|PPfN{9PA#?qQWF>3)-wo# z#7gpuk~4sUV7ekMIl-k-hlk_9p@#YFliCycRBB}$gl9_3keDIqprRbmHnox0W0THBITbP3WV&a$E=2ty=HC zG~lU%4Vyvhv(8`t6$1E0*UBqLX}#wBJ-5*yfkm5f;)9UGXU;IVux#NKo!U~v|J9nI INIBRa01d}caR2}S delta 262 zcmX@YbepN(Hze4XfrWvSfrEj)9ts$^86xEmFD7EaFd|O~5e?3FVL`LSWoFla!i+^pB%(XXOVY#|Cv7Vgj+nIcS=mWz)jegJ{NcwRtHdr?)!fd%N~+@9_s>UvhJ4xoY*{?l c_a*;>w04Ur*~_hX`+3@=-%$(;TmDA_07bKG(EtDd diff --git a/mods/MAPGEN/mcl_villages/schematics/lamp.mts b/mods/MAPGEN/mcl_villages/schematics/lamp.mts index c8d907ebad7a6bbd63574e62b695f22ba428e4b6..4d2d1a350553d2c23044298327b0a732395ac20e 100644 GIT binary patch delta 135 zcmcb}xQfx)Hze4XfrWvYft7)|9t1#)#LOZFf!ySr__Wl#R87mA7Gm?fkpCQ4$H|S2hK1|N>5BsSRuY@ft(Msr@^ZA>(f`b cUyAC_>fzuDpW`^CQP9(c=Lj2vl^M%J0Hnt+FaQ7m delta 152 zcmZ3*c#+Y`Hze4XfrWvYfsKKs9t;@R86o=1t~fGM|{mGuePqYH}cx45P?oLm-~VD8i^VF+gf^ z2NUn)O^njqC8ar;1@Yw>nI)+}t28Elu&=L(OFqCKArY}bLm=%zvV_Hf6AgTdd5NhB z&P{80I0Ea~>Q?Y12DV7P$WmOU(4DkuYT5+Hrb`Lx4~q1qBgDk^`hhL70nYDtbA;ghu9J#9O#wW*)8 z^HI@yjb@DtHg6tkJ5H*Wl=!eTUT;C<8=%pgj*M&pIb4ShOGJvObi9dU+tI&M;=|7A z{aNo?r=-2%k>Q!+@=P)2o$5UnrS3(sKM)uHfiI)B@y(rIRTli6Cmq;U zv@G%Kj2J;y+Wbg2PRSf-Um{ESgrhh198+Z$(HixiX< zUwar%7g;WBAl@GMh~s~!adN2hrky=4O$_sy+}12S=U|x7#K5E9)oB>O&cJZOJH`pj&0uP> z1CtiW4Qfd_rK$1xMadbNDGZWuD~n6=^HP(FGLy5D6N}1HQzkPq%1mZr6rcQnQGW7T zCLUQSuqFBVIaWED=@}*QU}J!43sOrM)IeTRDk;s$EC8CEn3tZ)APQHWUX+@e7Y|lB zxsFkqQGfC*MqQ?~w25mBK<=r}uSl&-jZaC;EUv7W^LE-zp(X2c%DcRJQPu3X*lhCRXB;PiQ2w$-vz%Vm=mOKnRj*k&5xD}MBb-x-P9JI&3$ z{+@RCBlq?d(>|SBH&yPE|9&HB)0El0ht$*#wB9*!_k(xC#+mO8cy8C9ZCID~{V{v` z_muxT=Y@fQm!fe(!O@R5WK9IktavYNOg8@eG|&93i1>~N`+Qdgs_?!1o#lIFmDHli h+_K*SdS4ZUa=yKB>y)6;nrSM3%P#Ma%lNWL2mrP94k`cu diff --git a/mods/MAPGEN/mcl_villages/schematics/library.mts b/mods/MAPGEN/mcl_villages/schematics/library.mts index b47e0b4138f53fbb43aa1887249002d9c1082149..2986a71625064e764e7d60cfeef3eacca8dba011 100644 GIT binary patch delta 587 zcmdnM_J>W^Hze4XfrWvGft`V?9s(GI8JH6@ix~KGlXK#e^NUiglJk?2a#9%-C+9Ls zPflf25fO$<6_@1ar6v_+CTCAR#VEta3zsO*&rg}$!DujXq4;DyMsd-kctZvOkZf9N zUUF)&6_}d*lu>=+F9V4Zprjy3vLwGKIRhvQrWy1mp4Mf|n^>h*UlEt=z}~|n(4lwk z&;hm<9iAiI+(sNm3Bmobb9xz>40RF&n4H*j-lZ_kI@h6i?$`m&mYj$qj!rWkH6=`K zl6Y0v>FjgB#Jz*@iN2!HozAYkrmoMd->h))W0TCh4JMq6 zBPA3*f^2HnLPs`<6qeU5JK9?rcUwp^tF=@(bTBe1emr;N08fdi zhObg`hxJW~8L-QnFxanW9QPr_*J1V`goEq;hrf zz8en@EBa-Z8yO{(t8<5a|6sI%r@^|jzuYfDtKn&$+?0yvjmH#p57!Hen7sJeA?R(F z4 zo~zejaC5M2ijD8riRG%YmNwai(SSKA-f-dv3D%N$Lk7i(0n!sa zR3@(07ZL<%D#!BNik zu+8$`?K@Q_{qk}VJ%U>Q?rht!?eE^8+viv(CkRf^-cYZ%_3q5@2dX<*Zakf|hHZE0 z(n8a)RR0avy5FmJt}>tNQ~ZD3YoV&`VaKdi ztdEfpWnX12@jRiP*-FEXPAgG%7{Li(cm9He#mP{5{nQox{#$U}c<+Wh& cY6bUc>r+oG7iG?N-CCZoR`(_A*T@N30RI{7F#rGn diff --git a/mods/MAPGEN/mcl_villages/schematics/medium_house.mts b/mods/MAPGEN/mcl_villages/schematics/medium_house.mts index 43ce2391b9d1952596c3ec5028d0d66dd7105926..85ef0f9031a47eb81c48356da3c63a7ab12e92d1 100644 GIT binary patch delta 543 zcmeytx{s~iHze4XfrWvCft`V?9s(Fd8JH6@ix~KGlXK#e^NUiglJk?2a#9(DKmz57 zIXT5pk$6J}agbPX2~d5p6_^6*04tV+>n<+I&r3}z%1q8qPAn=*O<~}LOO-GerKV0? zVZetFD$mbPnZzhEc^;$P#0DuKCC*$DZ#dbB(OFUg*{+<#q%mB$=?_?CSKR9 zuZT-tAi`m=!0FI4Ln8$R4^wSsrb9n$cx(~^efBXhZ>nQlz!b*Dr;&0r%W_w3PeN!8 z&l`tW1vTXuadu|4c!n2zi5qrsTu7TxE5kD*oYc6{jBReL7m zo1sC0P)ylsNbp6^$-)ul>x-?Aq|8ZSOn7(4mckEdhkgiTf&O}|Nqz5+Fp?1=v~RLa;PDNe^pgm)r@`r1K4J?Wi@23 zX1AJbQ|oK+`Qpo8Rj+OxcPQL(#hHogtjwH`4hj<=_LR3ZGWYcSc$1cra6tXM$A!B# nHXdFQo!`|Wo7`BUd*UoUoq$H z)K0!;1)er;=}pY#`RjLw%U=`9R?X|K$XQsQ^k?Z5e@hmDg=t|~a=Kq^&v&hS6lokP z*{1p9koLRM)%%Z?c^i3Fyn4;HZC}!3?W23XEq-_5ZRhbO=l2@+0>@t3JomkcK_1ttM8&UD*TRI{;>RkCAS=__^CZXt+$uhES;fm z{<&sp#QE}){)yKC$mA(7> Y9+`7p`pC1USv9EcxqQF)F2}8Y03u+yPXGV_ diff --git a/mods/MAPGEN/mcl_villages/schematics/small_house.mts b/mods/MAPGEN/mcl_villages/schematics/small_house.mts index d7b62529cb804c5fa99a9a99a8677c4f5cc46b9f..d09fbfe00ae358153475021d2d828a1689d93dac 100644 GIT binary patch delta 373 zcmcb}@{&c=Hze4XfrWt`1nVJyL13bT_+&Fi1>xe7#LS{%D=-zGoS&4GlR9yZ{NzAJ z{fQsMCtk9gSRgjJfl*S6K`=KtC%z=VC^;jw*a}QDh=PPr3@FdfPnj&sC{bS#mz;~r;o+Gp%r-b3RWwnb!oG0g(;bb^991M2ni(`5W=>?b@8b3O5a6`6 zQM8|zW2(UQrXOo~j{I!wZJgV9tEMiY<#%H%qu@0jo*k7FDjuk4$w{1Gxx-`QFxQ5s zL*nVNtRP#C2OF4I%Y+C>hsO5{uu4brD_sov_y51VMhyS5R|iEpqT}rwq!b((3f0T( zA9S-UxU9Htefk2m1Shkei4#tqabP{OB+7pco15E;muIF_Oz8Y{fsw)gOUhyZ^-Pa! delta 406 zcmaFKa*?IpHze4XfrWt+2-)jlfI)~sA~!iFJ~_WA)hZ>ks3g8Tvm_%vy(qD`n1L5X zhJiUTvxtEoE|#31l$4XoAPy2JE&<9FTY)K{SzrkfWQm+awxsy-{QQ*3_KXq}6XYg7 z5}$a)QbiD?rX;^8IU}{$3QRMIp=wKtpQx%nv01Ag>`a(FIf)R{fO-om=DZDg%h#;H zqf^pzuJ+fF>aVdgEbQ*^FrBQcn67=}$}<&LC5J{kq09*fo4a>)vDxg}vA4Z^g;BeV zA>P0&%b!TlJ(k@RndKY&#^P_iyt(qx9$nbE2@Yt zd{Mq%rp`!h)vMCB@~S^qC7%^*oRnFYdau~RWX55M``M>6GhAeZ*<)a#Pwp61DM1on=(n8^MWLk^NUigN{Uib z8H7RHtkUe%r2GmiC=D?nIU}{Wq}U2fG3ZTBVbo>JoBWDVZgMD-*u*TUiPudhD>4e# z3xNzMPt3^yD$P$y%1MnkgBXe;W@yA94N{2V*!cX?lGGvwKDevWa}tY-E8>zF7~R-P zID}H2gj16a=xd!&;JDrx&>bss)9%kRqXi6VY(b35%)%n|hu*aOn8BMPz|YJ+;Th{L z=_8^oQhF>RqG<`uT}DcsPG6KfO6-)IB|^4xFmIZ}!EDqpvqS2Yf#@TL**6zN%wd#2 z@YK9)h1!JsHy+eIX71){tUc3kG=G5r<4&I$je>ca%9He29xhr@mwe!%dB=anx)#mE zv z_K!Xvnx@TUj9GDrC;iAecCDV+X%ibY7&b9wN&DC?^V`4?$E-N%%!x3eG6p`;Gc2-x xC(Km7E4^8;EZ2u+@m#NMi5oj+HlA4F%Io%K){FxUGaEx3w#qOt*gdNb001J2L|^~_ delta 670 zcmeyw@s{1wHze4XfrWvaftP`+9vLu5Gf3nn=fo%H7o}RIWEPdgmuHq_#HSY}78f%x zCuSBg@S;dhlvSKOi&1LgMDfW2jH0T-aLMA5{JhkpqRixM1_7{OMrv_Mu~jmVn!Jh8 ze6j$OsIwqQq9nfvBxnVu8Kgl%#U((Cimkv@e0hF;N_>84NooBo}EscQ>ZgF}J(5Vw`E%^`*Eh$P(ot(xfCkplz!ez;cMP;ce6VDk>u4k047Xlek zo|uyZbY*^0Qch~TS;d^UVVy-nP3f7?ut+`qj+d5u$2f3@CPcG{HS{9J8 zTxZVPj=uYMjz2s2`Q{=chtvtW-*f-eU*94ZnzH=(+#4_7dc+pKzG>)&} zQvF^>oKNvRIq`MdlQkjfHQWAAXxb+cdHx)CrS2J7uX{D~#3wxLIK}W*pv*1$1fNSG zkeGY2FJkLIgS;7!jv0QI+xYpRdtH;wex>zNwheo%7aLmJp7M*ZZ_7J*?$XZ5*UB7M zPpCIPdd@Wbnt=88O;y60_Y&LYvfr<7O;>-m{rd~^6R%3xcNf`Se4Sh1RKF@@Wzf=7 zyq?d_>=I9W@j9&VYv=j)Yp&;Gm|leBzk9SnO;hfdckJb)BMT?%bH(Z@CI|9;eqQ2m rRAl>)_aza9d2yO^ixhN@t@_!{pX4@eqp|n5s29Iau5$K?0j-d`W&mMO-oiV;Y+q z+b0HLW|pRsVuKA#it0BM^kh`bnOTes42%zaX?l~En!xT9wx{nw+5<+XyaiHjTwja~ z6n4*KeUoOUboUIyw%KPktXhBk@$O$$6HNFv$?-@m*!2HDGw-VQ2@0`4QYAmkI&+}m kdMM8mW;c&rNesud#GDg0y?OKG#(^U((c%o3{uxFB0D@?)dH?_b delta 275 zcmX@Xe23Z0Hze4XfrWvMft`V)9s(Hn86Pgf$I&kPkkM4BDCu#uDl8Wx9Dy4 diff --git a/mods/MAPGEN/mcl_villages/utils.lua b/mods/MAPGEN/mcl_villages/utils.lua deleted file mode 100644 index 1d94ead0c..000000000 --- a/mods/MAPGEN/mcl_villages/utils.lua +++ /dev/null @@ -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