123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- 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 noisemap2 = {}
- local noisemap3 = {}
- local noisemap4 = {}
- local noisemap5 = {}
- --[[
- 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(minp, maxp, seed)
- local nstart = nethermapgen.NETHER_START
- local bstart = nethermapgen.BRIMSTONE_OCEAN
- local rstart = nethermapgen.BEDROCK_DEPTH
- -- Don't run for out-of-bounds mapchunks.
- local mindepth = nstart + 100
- if minp.y > mindepth and maxp.y > mindepth then return end
- -- Grab the voxel manipulator.
- local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
- vm:get_data(data) -- Read current map data.
-
- local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
- local area2 = VoxelArea:new{MinEdge=minp, MaxEdge=maxp}
-
- 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
-
- -- 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 sides3D = {x=side_len_x, y=side_len_y, z=side_len_z}
- local sides2D = {x=side_len_x, y=side_len_z}
- local bp3d = {x=x0, y=y0, z=z0}
- local bp2d = {x=x0, y=z0}
-
- -- 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)
- local perlin5 = minetest.get_perlin_map(nethermapgen.noise5param3d, sides3D)
- perlin5:get_3d_map_flat(bp3d, noisemap5)
-
- -- Localize commonly used functions.
- local floor = math.floor
- local ceil = math.ceil
- local abs = math.abs
-
- -- First mapgen pass.
- 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 rs_top = ceil(nstart+abs(n1)*64)
- local rs_bot = floor(nstart-abs(n1)*64)
-
- 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)
-
- -- First pass through column.
- 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)
-
- -- 3D noise.
- local np = area2:index(x, y, z)
- local n5 = noisemap5[np]
-
- if y <= rs_top then
- -- Get the type already generated at this position.
- local ip = data[vp]
-
- -- Using mapdata already generated by the C++ mapgen, convert regular nodes to nether types.
- if 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_lava
- elseif ip ~= c_air and ip ~= c_vine then -- Vines can cross chunk borders. Don't replace them.
- -- Generate rackstone layer between nether and underworld.
- if y >= rs_bot and y <= rs_top then
- data[vp] = c_mgrackstone
- elseif y < rs_bot then
- if abs(n5) < 0.015 then
- data[vp] = c_mgrackstone
- else
- data[vp] = c_mgredrack
- end
- else
- data[vp] = c_stone
- end
- end
-
- -- Generate the endless nether lava ocean, with islands.
- if y <= lakebed or y <= islandi then
- -- Fill in map below brimstone ocean & create islands.
- data[vp] = c_redrack
- elseif y <= lakelav then
- data[vp] = c_nlava -- Special lava for brimstone ocean.
- elseif y <= lakecel then
- -- Carve out horizontal cavern above brimstone ocean.
- data[vp] = c_air
- elseif ip == c_air and y > lakecel and y <= cavernf then
- if y <= (lakecel + 4) then
- -- Fill in huge ceiling holes created when huge caves
- -- intersect with the brimstone ocean realm.
- data[vp] = c_redrack
- else
- data[vp] = c_nlava
- end
- end
- end -- If Y coord is below nether start.
-
- end -- For all in Y coordinates.
- end -- For all in X coordinates.
- end -- For all in Z coordinates.
-
- -- Second mapgen pass, for things that need overgenerating.
- local ex1 = emax.x
- local ey1 = emax.y
- local ez1 = emax.z
- local ex0 = emin.x
- local ey0 = emin.y
- local ez0 = emin.z
-
- for z = ez0, ez1 do
- for x = ex0, ex1 do
- for y = ey0, ey1 do
- -- Get voxelmap indice.
- local vp = area:index(x, y, z)
- local ip = data[vp]
-
- -- Transform dungeons (over)-generated by the C++ mapgen.
- -- Also remove water.
- if y <= nstart then
- if 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_lava
- end
- end
-
- -- Bedrock layer.
- if y <= rstart+pr:next(1,pr:next(2, 3)) then
- 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. Sad but true. :(
- 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]
-
- -- 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, 5000) == 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, 400) == 0 and y > -30750 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, 10) == 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()
- 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"})
- firetree.create_firetree({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"})
- redshroom.create_shroom({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
- -- Use swap_node to avoid triggering the construction timer.
- swap_node(v, {name="nether:grass_" .. math_random(1, 3)})
- end
- for k, v in ipairs(chnk_pos_flower) do
- -- Use swap_node to avoid triggering the construction timer.
- swap_node(v, {name="nether:glowflower"})
- end
- end
|