mg = {} local DMAX = 20 local AREA_SIZE = 80 minetest.register_on_mapgen_init(function(mgparams) minetest.set_mapgen_params({mgname="singlenode", flags="nolight", flagmask="nolight"}) end) local cache = {} local function cliff(x, n) return 0.2*x*x - x + n*x - n*n*x*x - 0.01 * math.abs(x*x*x) + math.abs(x)*100*n*n*n*n end local function get_base_surface_at_point(x, z, vn, vh, ni, noise1, noise2, noise3, noise4) local index = 65536*x+z if cache[index] ~= nil then return cache[index] end cache[index] = 25*noise1[ni]+noise2[ni]*noise3[ni]/3 if noise4[ni] > 0.8 then cache[index] = cliff(cache[index], noise4[ni]-0.8) end if vn<40 then cache[index] = vh elseif vn<200 then cache[index] = (vh*(200-vn) + cache[index]*(vn-40))/160 end return cache[index] end local function surface_at_point(x, z, ...) return get_base_surface_at_point(x, z, unpack({...})) end local SMOOTHED = AREA_SIZE+2*DMAX local HSMOOTHED = AREA_SIZE+DMAX local INSIDE = AREA_SIZE-DMAX local function smooth(x, z, ...) local s=0 local w=0 for xi=-DMAX, DMAX do for zi=-DMAX, DMAX do local d2=xi*xi+zi*zi if d2=yy then add_leaves(data, a:index(xx, yy, zz), c_leaves) end end end end end function add_savannabush(data, a, x, y, z, minp, maxp, c_tree, c_leaves, pr) bh = pr:next(1, 2) bw = pr:next(2, 4) for xx=math.max(minp.x, x-bw), math.min(maxp.x, x+bw) do for zz=math.max(minp.z, z-bw), math.min(maxp.z, z+bw) do for yy=math.max(minp.y, y-bh), math.min(maxp.y, y+bh) do if pr:next(1, 100) < 95 and math.abs(xx-x) < pr:next(bh, bh+2)-math.abs(y-yy) and math.abs(zz-z) < pr:next(bh, bh+2)-math.abs(y-yy) then add_leaves(data, a:index(xx, yy, zz), c_leaves) for yyy=math.max(minp.y, yy-2), yy do add_leaves(data, a:index(xx, yyy, zz), c_leaves) end end end end end if x<=maxp.x and x>=minp.x and y<=maxp.y and y>=minp.y and z<=maxp.z and z>=minp.z then local vi = a:index(x, y, z) data[vi] = c_tree end end function add_pinetree(data, a, x, y, z, minp, maxp, c_tree, c_leaves, c_snow, pr) th = pr:next(9, 13) for yy=math.max(minp.y, y), math.min(maxp.y, y+th) do local vi = a:index(x, yy, z) data[vi] = c_tree end maxy = y+th for xx=math.max(minp.x, x-3), math.min(maxp.x, x+3) do for yy=math.max(minp.y, maxy-1), math.min(maxp.y, maxy-1) do for zz=math.max(minp.z, z-3), math.min(maxp.z, z+3) do if pr:next(1, 100) < 80 then add_leaves(data, a:index(xx, yy, zz), c_leaves, c_snow) add_leaves(data, a:index(xx, yy+1, zz), c_snow) end end end end for xx=math.max(minp.x, x-2), math.min(maxp.x, x+2) do for yy=math.max(minp.y, maxy), math.min(maxp.y, maxy) do for zz=math.max(minp.z, z-2), math.min(maxp.z, z+2) do if pr:next(1, 100) < 85 then add_leaves(data, a:index(xx, yy, zz), c_leaves, c_snow) add_leaves(data, a:index(xx, yy+1, zz), c_snow) end end end end for xx=math.max(minp.x, x-1), math.min(maxp.x, x+1) do for yy=math.max(minp.y, maxy+1), math.min(maxp.y, maxy+1) do for zz=math.max(minp.z, z-1), math.min(maxp.z, z+1) do if pr:next(1, 100) < 90 then add_leaves(data, a:index(xx, yy, zz), c_leaves, c_snow) add_leaves(data, a:index(xx, yy+1, zz), c_snow) end end end end if maxy+1<=maxp.y and maxy+1>=minp.y then add_leaves(data, a:index(x, maxy+1, z), c_leaves, c_snow) add_leaves(data, a:index(x, maxy+2, z), c_snow) end my = 0 for i=1,20 do xi = pr:next(x-3, x+2) yy = pr:next(maxy-6, maxy-5) zi = pr:next(z-3, z+2) if yy > my then my = yy end for xx=math.max(minp.x, xi), math.min(maxp.x, xi+1) do for zz=math.max(minp.z, zi), math.min(maxp.z, zi+1) do if minp.y<=yy and maxp.y>=yy then add_leaves(data, a:index(xx, yy, zz), c_leaves, c_snow) add_leaves(data, a:index(xx, yy+1, zz), c_snow) end end end end for xx=math.max(minp.x, x-2), math.min(maxp.x, x+2) do for yy=math.max(minp.y, my+1), math.min(maxp.y, my+1) do for zz=math.max(minp.z, z-2), math.min(maxp.z, z+2) do if pr:next(1, 100) < 85 then add_leaves(data, a:index(xx, yy, zz), c_leaves, c_snow) add_leaves(data, a:index(xx, yy+1, zz), c_snow) end end end end for xx=math.max(minp.x, x-1), math.min(maxp.x, x+1) do for yy=math.max(minp.y, my+2), math.min(maxp.y, my+2) do for zz=math.max(minp.z, z-1), math.min(maxp.z, z+1) do if pr:next(1, 100) < 90 then add_leaves(data, a:index(xx, yy, zz), c_leaves, c_snow) add_leaves(data, a:index(xx, yy+1, zz), c_snow) end end end end end dofile(minetest.get_modpath(minetest.get_current_modname()).."/we.lua") dofile(minetest.get_modpath(minetest.get_current_modname()).."/nodes.lua") dofile(minetest.get_modpath(minetest.get_current_modname()).."/rotate.lua") dofile(minetest.get_modpath(minetest.get_current_modname()).."/buildings.lua") dofile(minetest.get_modpath(minetest.get_current_modname()).."/villages.lua") dofile(minetest.get_modpath(minetest.get_current_modname()).."/ores.lua") local function get_biome_table(minp, humidity, temperature) l = {} for xi = -1, 1 do for zi = -1, 1 do mnp, mxp = {x=minp.x+xi*80,z=minp.z+zi*80}, {x=minp.x+xi*80+80,z=minp.z+zi*80+80} pr = PseudoRandom(get_bseed(mnp)) bxp, bzp = pr:next(mnp.x, mxp.x), pr:next(mnp.z, mxp.z) h, t = humidity:get2d({x=bxp, y=bzp}), temperature:get2d({x=bxp, y=bzp}) l[#l+1] = {x=bxp, z=bzp, h=h, t=t} end end return l end local function get_distance(x1, x2, z1, z2) return (x1-x2)*(x1-x2)+(z1-z2)*(z1-z2) end local function get_nearest_biome(biome_table, x, z) m = math.huge k = 0 for key, bdef in ipairs(biome_table) do local dist = get_distance(bdef.x, x, bdef.z, z) if dist0.4 then if biome_humidity<-0.4 then top = c_desert_sand top_layer = c_desert_sand second_layer = c_desert_stone if pr:next(1, 50) == 1 then above_top = c_cactus elseif pr:next(1, 50) == 1 then above_top = c_dry_shrub end elseif biome_humidity<0.4 then top = c_dry_grass top_layer = c_dirt second_layer = c_stone if (pr:next(1, 250) == 1 and y>12) or (pr:next(1, 1000) == 1 and y<=12) then above_top = c_savannasapling elseif (pr:next(1, 25) == 1 and y>12) or (pr:next(1, 50) == 1 and y<=12) then if pr:next(1, 80) > 100*(humidity+0.4) then above_top = c_dry_shrub elseif pr:next(1, 100) == 1 then above_top = "savannabush" end end else if pr:next(1, 14) == 1 then above_top = c_sapling elseif pr:next(1, 16) == 1 then above_top = c_junglesapling elseif pr:next(1, 30) == 1 then above_top = c_jungle_grass end top = c_grass top_layer = c_dirt second_layer = c_stone end elseif biome_temperature<-0.4 then above_top = c_snow top = c_dirt_snow top_layer = c_dirt second_layer = c_stone if biome_humidity>-0.4 then if pr:next(1, 40) == 1 then above_top = c_pinesapling end else if pr:next(1, 500) == 1 then above_top = c_pinesapling end end else if biome_humidity<-0.4 then if pr:next(1, 250) == 1 then above_top = c_sapling elseif pr:next(1, 60) == 1 then above_top = c_grasses[pr:next(1,4)] end elseif biome_humidity>0.4 then if pr:next(1, 250) == 1 then above_top = c_sapling elseif pr:next(1, 3) == 1 then above_top = c_grasses[pr:next(3,5)] end else if pr:next(1, 20) == 1 and y>0 then above_top = c_sapling end end top = c_grass top_layer = c_dirt second_layer = c_stone end end if y>=100 then above_top = c_air top = c_snow top_layer = c_snowblock end if y<0 then above_top = c_air end if y==0 then if top == c_grass then if pr:next(1, 10) == 1 then above_top = c_papyrus end end end if y<=maxp.y and y>=minp.y then local vi = a:index(x, y, z) if y >= 0 then data[vi] = top else data[vi] = top_layer end end if above_top == c_sapling then if not inside_village(x, z, vx, vz, vs, village_noise) then add_tree(data, a, x, y+1, z, treemin, treemax, c_tree, c_leaves, pr) else villages_to_grow[#villages_to_grow+1] = {x=x, y=y+1, z=z, content=c_sapling} end elseif above_top == c_junglesapling then if not inside_village(x, z, vx, vz, vs, village_noise) then add_jungletree(data, a, x, y+1, z, treemin, treemax, c_jungletree, c_jungleleaves, pr) else villages_to_grow[#villages_to_grow+1] = {x=x, y=y+1, z=z, content=c_junglesapling} end elseif above_top == c_savannasapling then if not inside_village(x, z, vx, vz, vs, village_noise) then add_savannatree(data, a, x, y+1, z, treemin, treemax, c_savannatree, c_savannaleaves, pr) else villages_to_grow[#villages_to_grow+1] = {x=x, y=y+1, z=z, content=c_savannasapling} end elseif above_top == "savannabush" then if not inside_village(x, z, vx, vz, vs, village_noise) then add_savannabush(data, a, x, y+1, z, treemin, treemax, c_savannatree, c_savannaleaves, pr) else villages_to_grow[#villages_to_grow+1] = {x=x, y=y+1, z=z, content="savannabush"} end elseif above_top == c_pinesapling then if not inside_village(x, z, vx, vz, vs, village_noise) then add_pinetree(data, a, x, y+1, z, treemin, treemax, c_pinetree, c_pineleaves, c_snow, pr) else if y+1<=maxp.y and y+1>=minp.y then local vi = a:index(x, y+1, z) data[vi] = c_snow end villages_to_grow[#villages_to_grow+1] = {x=x, y=y+1, z=z, content=c_pinesapling} end elseif above_top == c_cactus then if not inside_village(x, z, vx, vz, vs, village_noise) then ch = pr:next(1, 4) for yy = math.max(y+1, minp.y), math.min(y+ch, maxp.y) do data[a:index(x, yy, z)] = c_cactus end else villages_to_grow[#villages_to_grow+1] = {x=x, y=y+1, z=z, content=c_cactus} end elseif above_top == c_papyrus then if not inside_village(x, z, vx, vz, vs, village_noise) then ch = pr:next(2, 4) for yy = math.max(y+1, minp.y), math.min(y+ch, maxp.y) do data[a:index(x, yy, z)] = c_papyrus end else villages_to_grow[#villages_to_grow+1] = {x=x, y=y+1, z=z, content=c_papyrus} end else if y+1<=maxp.y and y+1>=minp.y then local vi = a:index(x, y+1, z) data[vi] = above_top end end if y<0 and minp.y<=0 and maxp.y>y then for yy = math.max(y+1, minp.y), math.min(0, maxp.y) do local vi = a:index(x, yy, z) data[vi] = c_water end if maxp.y>=0 then data[a:index(x, 0, z)] = liquid_top end end local tl = math.floor((noise_top_layer[ni]+2.5)*2) if y-tl-1<=maxp.y and y-1>=minp.y then for yy = math.max(y-tl-1, minp.y), math.min(y-1, maxp.y) do local vi = a:index(x, yy, z) data[vi] = top_layer end end local sl = math.floor((noise_second_layer[ni]+5)*3) if y-sl-1<=maxp.y and y-tl-2>=minp.y then for yy = math.max(y-sl-1, minp.y), math.min(y-tl-2, maxp.y) do local vi = a:index(x, yy, z) data[vi] = second_layer end end if y-sl-2>=minp.y then for yy = minp.y, math.min(y-sl-2, maxp.y) do local vi = a:index(x, yy, z) data[vi] = c_stone end end end end local va = VoxelArea:new{MinEdge=minp, MaxEdge=maxp} for _, ore_sheet in ipairs(mg.registered_ore_sheets) do local sidelen = maxp.x - minp.x + 1 local np = copytable(ore_sheet.noise_params) np.seed = np.seed + minp.y local pm = minetest.get_perlin_map(np, {x=sidelen, y=sidelen, z=1}) local map = pm:get2dMap_flat({x = minp.x, y = minp.z}) local ni = 0 local trh = ore_sheet.threshhold local wherein = minetest.get_content_id(ore_sheet.wherein) local ore = minetest.get_content_id(ore_sheet.name) local hmin = ore_sheet.height_min local hmax = ore_sheet.height_max local tmin = ore_sheet.tmin local tmax = ore_sheet.tmax for z = minp.z, maxp.z do for x = minp.x, maxp.x do ni = ni+1 local noise = map[ni] if noise > trh then local thickness = pr:next(tmin, tmax) local y0 = math.floor(minp.y + (noise-trh)*4) for y = math.max(y0, hmin), math.min(y0+thickness-1, hmax) do local vi = a:index(x, y, z) if data[vi] == wherein or wherein == c_ignore then data[vi] = ore end end end end end end for _, ore in ipairs(mg.registered_ores) do generate_vein(minetest.get_content_id(ore.name), minetest.get_content_id(ore.wherein), minp, maxp, ore.seeddiff, ore, data, a, va) end to_add = generate_village(vx, vz, vs, vh, minp, maxp, data, a, village_noise, villages_to_grow) vm:set_data(data) vm:calc_lighting( {x=minp.x-16, y=minp.y, z=minp.z-16}, {x=maxp.x+16, y=maxp.y, z=maxp.z+16} ) vm:write_to_map(data) local meta for _, n in pairs(to_add) do minetest.set_node(n.pos, n.node) if n.meta ~= nil then meta = minetest.get_meta(n.pos) meta:from_table(n.meta) if n.node.name == "default:chest" then inv = meta:get_inventory() items = inv:get_list("main") for i=1, inv:get_size("main") do inv:set_stack("main", i, ItemStack("")) end numitems = pr:next(3, 20) for i=1,numitems do ii = pr:next(1, #items) prob = items[ii]:get_count() % 2 ^ 8 stacksz = math.floor(items[ii]:get_count() / 2 ^ 8) if pr:next(0, prob) == 0 and stacksz>0 then stk = ItemStack({name=items[ii]:get_name(), count=pr:next(1, stacksz), wear=items[ii]:get_count(), metadata=items[ii]:get_metadata()}) local ind = pr:next(1, inv:get_size("main")) while not inv:get_stack("main",ind):is_empty() do ind = pr:next(1, inv:get_size("main")) end inv:set_stack("main", ind, stk) end end end end end end) mg.registered_ores = {} function mg.register_ore(oredef) if oredef.wherein == nil then oredef.wherein = "ignore" end if DEBUG then oredef.wherein = "ignore" oredef.maxheight = 31000 end mg.registered_ores[#mg.registered_ores+1] = oredef end mg.registered_ore_sheets = {} function mg.register_ore_sheet(oredef) if oredef.wherein == nil then oredef.wherein = "ignore" end if DEBUG then oredef.wherein = "ignore" oredef.height_max = 31000 end mg.registered_ore_sheets[#mg.registered_ore_sheets+1] = oredef end mg.register_ore({ name = "air", seeddiff = 1234, maxhdistance = 70, maxvdistance = 70, maxheight = -3, seglenghtn = 15, seglenghtdev = 6, segincln = 0.2, segincldev = 0.6, turnangle = 57, forkturnangle = 57, numperblock = 5, numbranchesn = 2, numbranchesdev = 0, mothersizen = -1, mothersizedev = 0, sizen = 100, sizedev = 30, radius = 2.3 }) mg.register_ore({ name = "default:stone_with_iron", wherein = "default:stone", seeddiff = 0, maxvdistance = 10.5, maxheight = -16, seglenghtn = 15, seglenghtdev = 6, segincln = 0, segincldev = 0.6, turnangle = 57, forkturnangle = 57, numperblock = 2.5 }) mg.register_ore({ name = "default:stone_with_coal", wherein = "default:stone", seeddiff = 1, maxvdistance = 10, sizen = 54, sizedev = 27, maxheight = 64, seglenghtn = 15, seglenghtdev = 6, segincln = 0, segincldev = 0.36, turnangle = 57, forkturnangle = 57, radius = 1, numperblock = 6 }) mg.register_ore({ name = "default:stone_with_mese", wherein = "default:stone", seeddiff = 2, maxvdistance = 50, sizen = 7, sizedev = 3, maxheight = -128, seglenghtn = 2, seglenghtdev = 1, segincln = 4, segincldev = 1, turnangle = 57, forkturnangle = 57, numperblock = 0.8, numbranchesn = 2, numbranchesdev = 1, fork_chance = 0.1, mothersizen = 0, mothersizedev = 0 }) mg.register_ore({ name = "default:mese", wherein = "default:stone", seeddiff = 3, maxvdistance = 50, sizen = 3, sizedev = 1, maxheight = -1024, seglenghtn = 2, seglenghtdev = 1, segincln = 4, segincldev = 1, turnangle = 57, forkturnangle = 57, numbranchesn = 2, numbranchesdev = 1, fork_chance = 0.1, radius = 1 }) mg.register_ore({ -- Same parameters exactly as the previous one so it spawns inside name = "default:lava_source", wherein = "default:mese", seeddiff = 3, maxvdistance = 50, sizen = 3, sizedev = 1, maxheight = -1024, seglenghtn = 2, seglenghtdev = 1, segincln = 4, segincldev = 1, turnangle = 57, forkturnangle = 57, numbranchesn = 2, numbranchesdev = 1, fork_chance = 0.1, mothersizen = 0, mothersizedev = 0 }) mg.register_ore({ name = "default:stone_with_copper", wherein = "default:stone", seeddiff = 4, maxvdistance = 10.5, maxheight = -16, seglenghtn = 15, seglenghtdev = 6, segincln = 0, segincldev = 0.6, turnangle = 57, forkturnangle = 57, numperblock = 2 }) mg.register_ore({ name = "default:stone_with_diamond", wherein = "default:stone", seeddiff = 5, maxvdistance = 50, sizen = 20, sizedev = 5, maxheight = -256, seglenghtn = 4, seglenghtdev = 2, segincln = 0.3, segincldev = 0.1, turnangle = 57, forkturnangle = 57, numbranchesn = 2, numbranchesdev = 1, fork_chance = 0.1, radius = 1 }) mg.register_ore({ name = "default:stone_with_gold", wherein = "default:stone", seeddiff = 17, maxvdistance = 10, sizen = 30, sizedev = 8, maxheight = -256, seglenghtn = 8, seglenghtdev = 4, segincln = 0.6, segincldev = 0.4, turnangle = 57, forkturnangle = 57, numbranchesn = 2, numbranchesdev = 1, fork_chance = 0.1, radius = 1 }) mg.register_ore({ name = "default:clay", wherein = "default:dirt", seeddiff = 6, maxvdistance = 10.5, maxheight = 0, minheight = -50, sizen = 50, sizedev = 20, seglenghtn = 15, seglenghtdev = 6, segincln = 0, segincldev = 0.6, turnangle = 57, forkturnangle = 57, numperblock = 1, radius = 1.5 }) mg.register_ore({ name = "default:lava_source", seeddiff = 7, maxhdistance = 20, maxvdistance = 70, maxheight = -100, seglenghtn = 2, seglenghtdev = 1, segincln = -5, segincldev = 2, turnangle = 57, forkturnangle = 57, numperblock = 1, numbranchesn = 2, numbranchesdev = 1, mothersizen = 5, mothersizedev = 3, sizen = 8, sizedev = 2, radius = 2.3 }) if minetest.get_modpath("moreores") ~= nil then mg.register_ore({ name = "moreores:mineral_tin", wherein = "default:stone", seeddiff = 8, maxvdistance = 10.5, maxheight = 8, seglenghtn = 15, seglenghtdev = 6, segincln = 0, segincldev = 0.6, turnangle = 57, forkturnangle = 57, numperblock = 2 }) mg.register_ore({ name = "moreores:mineral_silver", wherein = "default:stone", seeddiff = 9, maxvdistance = 10.5, maxheight = -2, seglenghtn = 15, seglenghtdev = 6, sizen = 60, sizedev = 30, segincln = 0, segincldev = 0.6, turnangle = 57, forkturnangle = 57, numperblock = 2 }) mg.register_ore({ name = "moreores:mineral_mithril", wherein = "default:stone", seeddiff = 9, maxvdistance = 10.5, maxheight = -512, seglenghtn = 1, seglenghtdev = 2, sizen = 5, sizedev = 3, segincln = 0, segincldev = 0.6, turnangle = 57, }) end if minetest.get_modpath("technic") ~= nil then mg.register_ore({ name = "technic:mineral_uranium", wherein = "default:stone", seeddiff = 11, maxvdistance = 10.5, maxheight = -80, minheight = -300, sizen = 20, sizedev = 10, seglenghtn = 3, seglenghtdev = 1, segincln = 0.4, segincldev = 0.6, turnangle = 57, numperblock = 1, fork_chance = 0 }) mg.register_ore({ name = "technic:mineral_chromium", wherein = "default:stone", seeddiff = 12, maxvdistance = 10.5, maxheight = -100, sizen = 50, sizedev = 20, seglenghtn = 8, seglenghtdev = 3, segincln = 0, segincldev = 0.6, turnangle = 57, forkturnangle = 57, numperblock = 2 }) mg.register_ore({ name = "technic:mineral_zinc", wherein = "default:stone", seeddiff = 13, maxvdistance = 10.5, maxheight = 2, seglenghtn = 15, seglenghtdev = 6, segincln = 0, segincldev = 0.6, turnangle = 57, forkturnangle = 57, numperblock = 2 }) if technic.config:get_bool("enable_granite_generation") then mg.register_ore_sheet({ name = "technic:granite", wherein = "default:stone", height_min = -31000, height_max = -150, tmin = 3, tmax = 6, threshhold = 0.4, noise_params = {offset=0, scale=15, spread={x=130, y=130, z=130}, seed=24, octaves=3, persist=0.70} }) end if technic.config:get_bool("enable_marble_generation") then mg.register_ore_sheet({ name = "technic:marble", wherein = "default:stone", height_min = -31000, height_max = -50, tmin = 3, tmax = 6, threshhold = 0.4, noise_params = {offset=0, scale=15, spread={x=130, y=130, z=130}, seed=23, octaves=3, persist=0.70} }) end end