123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477 |
- nethermapgen = {}
- nethermapgen.modpath = minetest.get_modpath("nethermapgen")
- nethermapgen.firetree_modpath = minetest.get_modpath("firetree")
- nethermapgen.redshroom_modpath = minetest.get_modpath("redshroom")
- -- These are copied in the init script, they MUST match.
- nethermapgen.NETHER_START = -25000
- nethermapgen.BRIMSTONE_OCEAN = -30800
- nethermapgen.BEDROCK_DEPTH = -30900
- dofile(nethermapgen.modpath .. "/noise.lua")
- dofile(nethermapgen.modpath .. "/functions.lua")
- local set_node = minetest.set_node
- local get_node = minetest.get_node
- local swap_node = minetest.swap_node
- local ipairs = ipairs
- local math_random = math.random
- -- Content IDs used with the voxel manipulator.
- local c_air = minetest.get_content_id("air")
- local c_ignore = minetest.get_content_id("ignore")
- local c_stone = minetest.get_content_id("default:stone")
- -- These 2 types are placed at and below the level of the brimstone ocean.
- -- They disallow the C++ cavegen from running.
- local c_redrack = minetest.get_content_id("rackstone:redrack")
- local c_rackstone = minetest.get_content_id("rackstone:rackstone")
- -- These 2 types are placed above the brimstone ocean.
- -- The C++ cavegen is allowed to run in these nodes.
- local c_mgredrack = minetest.get_content_id("rackstone:mg_redrack")
- local c_mgrackstone = minetest.get_content_id("rackstone:mg_rackstone")
- local c_whitestone = minetest.get_content_id("whitestone:stone")
- local c_mossycobble = minetest.get_content_id("default:mossycobble")
- local c_cobble = minetest.get_content_id("default:cobble")
- local c_netherbrick = minetest.get_content_id("rackstone:brick")
- local c_cobblestair = minetest.get_content_id("stairs:stair_cobble")
- local c_netherstair = minetest.get_content_id("stairs:stair_rackstone_brick")
- local c_water = minetest.get_content_id("default:water_source")
- local c_waterflow = minetest.get_content_id("default:water_flowing")
- local c_lava = minetest.get_content_id("default:lava_source")
- local c_nlava = minetest.get_content_id("lbrim:lava_source")
- local c_lavaflow = minetest.get_content_id("default:lava_flowing")
- local c_obsidian = minetest.get_content_id("default:obsidian")
- local c_vine = minetest.get_content_id("nethervine:vine")
- local c_bedrock = minetest.get_content_id("bedrock:bedrock")
- -- Externally located tables for performance.
- local data = {}
- local noisemap1 = {}
- local noisemap1_full = {}
- local noisemap2 = {}
- local noisemap3 = {}
- local noisemap3_full = {}
- local noisemap4 = {}
- local noisemap5 = {}
- local noisemap5_full = {}
- --[[
- Notes on mapgen function. IMPORTANT!
- The code loops through all positions in the mapchunk being generated *twice*, once to generate the nether,
- and the second time to repair problems at chunk borders caused by caves overgenerating in the C++ mapgen.
- These two loops work together, and must be understood together, since the loop which overgenerates can touch
- chunks previously generated by the first 'normal' loop.
- This 'hack' would not be necessary if we were using Singlenode for the C++ mapgen.
- However, we're using Valleys, so the Lua mapgen must work nicely with it.
- --]]
- nethermapgen.generate_realm = function(vm, minp, maxp, seed)
- local nstart = nethermapgen.NETHER_START
- local bstart = nethermapgen.BRIMSTONE_OCEAN
- local rstart = nethermapgen.BEDROCK_DEPTH
- local gennotify_data = {
- minp = minp,
- maxp = maxp,
- }
- -- Don't run for out-of-bounds mapchunks.
- -- This code makes nethermapgen run for ALL chunks from start, to bottom of world.
- local mindepth = nstart + 100
- if minp.y > mindepth and maxp.y > mindepth then return end
- -- Grab the voxel manipulator.
- local emin, emax = vm:get_emerged_area()
- vm:get_data(data) -- Read current map data.
- local pr = PseudoRandom(seed + 65)
-
- local x1 = maxp.x
- local y1 = maxp.y
- local z1 = maxp.z
- local x0 = minp.x
- local y0 = minp.y
- local z0 = minp.z
- -- To be used with noisemaps as needed.
- local area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
- local area2 = VoxelArea:new({MinEdge={x=x0, y=y0, z=z0}, MaxEdge={x=x1, y=y1, z=z1}})
-
- -- Compute side lengths.
- local side_len_x = ((x1-x0)+1)
- local side_len_y = ((y1-y0)+1)
- local side_len_z = ((z1-z0)+1)
- local side_len_x_full = ((emax.x-emin.x)+1)
- local side_len_y_full = ((emax.y-emin.y)+1)
- local side_len_z_full = ((emax.z-emin.z)+1)
- local sides3D = {x=side_len_x, y=side_len_y, z=side_len_z}
- local sides3D_full = {x=side_len_x_full, y=side_len_y_full, z=side_len_z_full}
- local sides2D = {x=side_len_x, y=side_len_z}
- local sides2D_full = {x=side_len_x_full, y=side_len_z_full}
- local bp3d = {x=x0, y=y0, z=z0}
- local bp3d_full = {x=emin.x, y=emin.y, z=emin.z}
- local bp2d = {x=x0, y=z0}
- local bp2d_full = {x=emin.x, y=emin.z}
-
- -- Get noisemaps.
- local perlin1 = minetest.get_perlin_map(nethermapgen.noise1param2d, sides2D)
- perlin1:get_2d_map_flat(bp2d, noisemap1)
- local perlin2 = minetest.get_perlin_map(nethermapgen.noise2param2d, sides2D)
- perlin2:get_2d_map_flat(bp2d, noisemap2)
- local perlin3 = minetest.get_perlin_map(nethermapgen.noise3param2d, sides2D)
- perlin3:get_2d_map_flat(bp2d, noisemap3)
- local perlin4 = minetest.get_perlin_map(nethermapgen.noise4param2d, sides2D)
- perlin4:get_2d_map_flat(bp2d, noisemap4)
- -- Not currently used.
- --local perlin5 = minetest.get_perlin_map(nethermapgen.noise5param3d, sides3D)
- --perlin5:get_3d_map_flat(bp3d, noisemap5)
-
- -- Some noisemaps need a full emin/emax version.
- local perlin1_full = minetest.get_perlin_map(nethermapgen.noise1param2d, sides2D_full)
- perlin1_full:get_2d_map_flat(bp2d_full, noisemap1_full)
- local perlin3_full = minetest.get_perlin_map(nethermapgen.noise3param2d, sides2D_full)
- perlin3_full:get_2d_map_flat(bp2d_full, noisemap3_full)
- local perlin5_full = minetest.get_perlin_map(nethermapgen.noise5param3d, sides3D_full)
- perlin5_full:get_3d_map_flat(bp3d_full, noisemap5_full)
- -- Localize commonly used functions.
- local floor = math.floor
- local ceil = math.ceil
- local abs = math.abs
- -- Pre-pass: convert stuff from the C++ mapgen to nether nodes.
- -- Do NOT modify terrain shape in this pass! (Except for the hack, see hack.)
- -- We have to scan through the overgenerated edges because those will contain
- -- default nodes as well.
- for z = emin.z, emax.z do
- for x = emin.x, emax.x do
- -- Get index into 2D noise arrays.
- local nx = (x-emin.x)
- local nz = (z-emin.z)
- local ni2 = (side_len_z_full*nz+nx)
- ni2 = ni2 + 1 -- Lua arrays start indexing at 1, not 0. Urrrrgh. >:(
- local n1 = noisemap1_full[ni2]
- -- Calculate the variance at the top of the nether's cavern realm,
- -- where it merges with default stone caverns.
- local rs_top = ceil(nstart+abs(n1)*64)
- local rs_bot = floor(nstart-abs(n1)*64)
- for y = emin.y, emax.y do
- local vp = area:index(x, y, z)
- -- Get the type already generated at this position.
- local ip = data[vp]
- -- Note: sometimes these will be nil, because of accessing outside the array.
- -- (We are scanning through the emin/emax range.)
- local iu = data[area:index(x, y+1, z)]
- local id = data[area:index(x, y-1, z)]
- -- Defines rackstone veins all throughout the nether.
- local n5 = noisemap5_full[area:index(x, y, z)]
- -- Using mapdata already generated by the C++ mapgen, convert regular nodes to nether types.
- if ip == c_stone then
- if y >= rs_bot and y <= rs_top then
- -- Top of the nether where it meets default caverns.
- data[vp] = c_mgrackstone
- elseif y < rs_bot then
- -- Regular rackstone veins run throughout nether.
- if abs(n5) < 0.025 then
- data[vp] = c_mgrackstone
- else
- -- Everything else is redrack.
- data[vp] = c_mgredrack
- end
- end
- elseif ip == c_cobble or ip == c_mossycobble then
- data[vp] = c_netherbrick
- elseif ip == c_cobblestair then
- data[vp] = c_netherstair
- elseif ip == c_water or ip == c_waterflow then
- data[vp] = c_air
- elseif ip == c_lava or ip == c_lavaflow then
- data[vp] = c_air
- end
- -- Get rid of ores generated by C++ (we use our own).
- -- WARNING: this creates bugs because it captures too many nodes, including our own,
- -- from neighboring chunks!
- --if ip ~= c_air and ip ~= c_ignore then
- -- data[vp] = c_mgrackstone
- --end
- -- HACK:
- -- Get rid of the <BEEP> flat horizontal slabs that appear at chunk top/bot edges
- -- whenever emerge threads are more than 1. We have to do this *indiscriminately*,
- -- which unfortunately modifies the terrain shape more than is actually necessary.
- if ip == c_stone or ip == c_mgredrack or ip == c_redrack or ip == c_mgrackstone or ip == c_rackstone then
- if (id == c_air or id == c_ignore) and (iu == c_air or iu == c_ignore) then
- data[vp] = c_air
- end
- end
- end
- end
- end
- -- Pass the first. Here, I modify the terrain shape (minp/maxp range only) to
- -- generate the nether sea, its ceiling, and the cavern floor directly above.
- for z = z0, z1 do
- for x = x0, x1 do
- -- Get index into 2D noise arrays.
- local nx = (x-x0)
- local nz = (z-z0)
- local ni2 = (side_len_z*nz+nx)
- ni2 = ni2 + 1 -- Lua arrays start indexing at 1, not 0. Urrrrgh. >:(
- local n1 = noisemap1[ni2]
- local n2 = noisemap2[ni2]
- local n3 = noisemap3[ni2]
- local n4 = noisemap4[ni2]
- local lakecel = bstart + 30
- local cavernf = bstart + 40
- local lakelav = bstart
- local lakebed = bstart - 2
- local islandi = bstart - 2
- if n4 > -0.3 then
- if abs(n2) > 0.6 then
- islandi = bstart + 5
- islandi = islandi + pr:next(0, pr:next(1, 2))
- islandi = islandi + floor(n1*4)
- -- Create random holes.
- if pr:next(1, 100) == 1 then islandi = bstart - 2 end
- elseif abs(n2) > 0.5 then
- islandi = islandi + pr:next(3, 5)
- end
- end
- lakecel = lakecel - pr:next(0, 1+floor(abs(n3) * 3.5))
- lakecel = lakecel + floor(abs(n1) * 6)
- -- For whole column:
- for y = y0, y1 do
- local vp = area:index(x, y, z)
- -- Generate the endless nether lava ocean, with islands.
- if y <= lakebed or y <= islandi then
- -- Fill in map below brimstone ocean & create islands.
- -- Important: NOT using mg_redrack here, because I don't want C++
- -- caves/dungeons carving through this!
- data[vp] = c_redrack
- elseif y <= lakelav then
- -- Special lava for brimstone ocean.
- -- Right around islands.
- data[vp] = c_nlava
- elseif y <= lakecel then
- -- Carve out horizontal cavern above brimstone ocean.
- -- Note: we fix the ceiling in a later pass.
- data[vp] = c_air
- end
- end
- end
- end
-
- -- Pass the second. Generate the non-cave-carvable ceiling above the
- -- nether sea. To prevent C++ caves cutting through the nethersea roof, this
- -- has to be overgenerated.
- for z = emin.z, emax.z do
- for x = emin.x, emax.x do
- -- Get index into 2D noise arrays.
- local nx = (x-emin.x)
- local nz = (z-emin.z)
- local ni2 = (side_len_z_full*nz+nx)
- ni2 = ni2 + 1 -- Lua arrays start indexing at 1, not 0. Urrrrgh. >:(
- local n1 = noisemap1_full[ni2]
- local n3 = noisemap3_full[ni2]
- local lakecel = bstart + 30
- local cavernf = bstart + 40
- lakecel = lakecel - pr:next(0, 1+floor(abs(n3) * 3.5))
- lakecel = lakecel + floor(abs(n1) * 5)
- -- For whole column:
- for y = emin.y, emax.y do
- if y > lakecel and y <= cavernf then
- local vp = area:index(x, y, z)
- -- Fill in huge ceiling holes created when huge caves
- -- intersect with the brimstone ocean realm. This "floor" itself
- -- supports a second lava ocean in the cavern layers.
- local f1 = lakecel + 1
- local f2 = lakecel + 5
- if y >= f1 and y <= f2 then
- -- Important: NOT using mg_redrack here, because I don't want C++
- -- caves/dungeons carving through this!
- data[vp] = c_redrack
- elseif y > f2 and y <= cavernf then
- if data[vp] == c_air then
- data[vp] = c_nlava
- end
- end
- end
- end
- end
- end
- -- Generate the bedrock layer. This MUST overwrite everything else!
- for z = emin.z, emax.z do
- for x = emin.x, emax.x do
- for y = emin.y, emax.y do
- if y <= rstart+pr:next(1,pr:next(2, 3)) then
- local vp = area:index(x, y, z)
- data[vp] = c_bedrock
- end
- end
- end
- end
-
- -- These tables will be filled with positions for decorations,
- -- to be placed after the voxel manipulator code finishes.
- local chnk_pos_flame = {}
- local chnk_pos_crystal = {}
- local chnk_pos_tree = {}
- local chnk_pos_shroom = {}
- local chnk_pos_vine = {}
- local chnk_pos_grass = {}
- local chnk_pos_flower = {}
-
- local is_netherock = function(ip)
- if ip == c_redrack or
- ip == c_rackstone or
- ip == c_mgredrack or
- ip == c_mgrackstone then
- return true
- else
- return false
- end
- end
-
- -- Final mapgen pass, for finding floors and ceilings.
- -- Note: this has to be a seperate pass because otherwise the code
- -- will find floors and ceilings where there aren't any.
- for x = x0, x1 do
- for z = z0, z1 do
- for y = y0, y1 do
- local vp = area:index(x, y, z)
- local vu = area:index(x, y+1, z)
- local vd = area:index(x, y-1, z)
-
- local ip = data[vp]
- local iu = data[vu]
- local id = data[vd]
-
- local tree_chance = 5000
- local flower_chance = 400
- local vine_chance = 10
- local cavernf = bstart + 41
- if y >= cavernf and y <= cavernf + 7 then
- tree_chance = 70 -- Increase trees.
- flower_chance = 200 -- Increase flowers.
- vine_chance = 30 -- Reduce vines.
- end
- -- Found floor.
- if is_netherock(ip) and iu == c_air then
- if pr:next(0, 2000) == 0 then
- chnk_pos_flame[#chnk_pos_flame+1] = {x=x, y=y+1, z=z}
- elseif pr:next(0, tree_chance) == 0 then
- chnk_pos_tree[#chnk_pos_tree+1] = {x=x, y=y+1, z=z}
- elseif pr:next(0, 3000) == 0 then
- chnk_pos_shroom[#chnk_pos_shroom+1] = {x=x, y=y+1, z=z}
- elseif pr:next(0, 200) == 0 then
- chnk_pos_grass[#chnk_pos_grass+1] = {x=x, y=y+1, z=z}
- elseif pr:next(0, flower_chance) == 0 and y > -30760 then
- chnk_pos_flower[#chnk_pos_flower+1] = {x=x, y=y+1, z=z}
- end
- end
-
- -- Found roof.
- if is_netherock(ip) and id == c_air then
- if pr:next(0, 4000) == 0 then
- chnk_pos_crystal[#chnk_pos_crystal+1] = {x=x, y=y-1, z=z}
- elseif pr:next(0, vine_chance) == 0 then
- chnk_pos_vine[#chnk_pos_vine+1] = {x=x, y=y-1, z=z}
- end
- end
- end
- end
- end
-
- -- Finalize voxel manipulator.
- vm:set_data(data)
- minetest.generate_ores(vm, minp, maxp)
- vm:set_lighting({day=0, night=0})
- vm:calc_lighting(emin, emax, true)
- vm:update_liquids()
- --vm:write_to_map()
-
- for k, v in ipairs(chnk_pos_flame) do
- nethermapgen.scatter_flames(v)
- end
-
- for k, v in ipairs(chnk_pos_tree) do
- local p = table.copy(v)
- p.y = p.y - 1
- set_node(p, {name="rackstone:dauthsand"})
- nethermapgen.create_firetree(vm, {x=p.x, y=p.y+1, z=p.z})
- end
-
- for k, v in ipairs(chnk_pos_shroom) do
- local p = table.copy(v)
- p.y = p.y - 1
- set_node(p, {name="rackstone:dauthsand"})
- nethermapgen.create_shroom(vm, {x=p.x, y=p.y+1, z=p.z})
- end
-
- for k, v in ipairs(chnk_pos_crystal) do
- nethermapgen.place_crystal(v)
- end
-
- for k, v in ipairs(chnk_pos_vine) do
- local p = table.copy(v)
- local r = pr:next(2, 7)
- for i = 1, r, 1 do
- if get_node(p).name ~= "air" then
- break
- end
- set_node(p, {name="nethervine:vine"})
- p.y = p.y - 1
- end
- end
- for k, v in ipairs(chnk_pos_grass) do
- swap_node(v, {name="nether:grass_" .. math_random(1, 3)})
- end
- for k, v in ipairs(chnk_pos_flower) do
- swap_node(v, {name="nether:glowflower"})
- end
- minetest.save_gen_notify("nether:mapgen_info", gennotify_data)
- end
- -- Register the mapgen callback.
- minetest.register_on_generated(function(...)
- nethermapgen.generate_realm(...)
- end)
|