diff --git a/README.txt b/README.txt index b697781..e90c2d2 100644 --- a/README.txt +++ b/README.txt @@ -1,14 +1,4 @@ -Release thread http://forum.minetest.net/viewtopic.php?id=5159 -For latest stable Minetest and compatible back to 0.4.3. -Depends default. -License WTFPL. - -* Meru mod is a vertical 1 dimensional realm, 1D referring to large scale structure, and can act as a vertical connector between horizontal realms, such as the ground and the floatlands. - -* A single spike shaped mountain is created in newly generated chunks, at a random location within a chosen area; by default this area is +/-1024 for use in a new world, to add a mountain to an existing world you need to edit these area parameters to a completely ungenerated part of your world. - -* For testing this mod or for cheating edit parameter COORD = true, the co-ordinates of the mountain will be printed to terminal while within the generation area. - -* No new nodes, the mountain is a hollow cone made of stone and desert stone, with a smooth transition across biome boundaries creating the red stripes. By default the height is 1km, but since i have increased the maximum width to 3x3 chunks the mountain can still look well proportioned when 2km. There are a few cave entrances on the surface, these 'fissure system' caves expand under the surface helping the creation of a path upwards. If the mountain generates over water you can use the central conical void to jump down the last few hundred metres. - -* There are many parameters for fine tuning the structure, some parameters change smoothly with height or distance from the center. Reducing noise to zero at the center creates a perfect spike as a summit. Constant noise throughout often creates floating islands at the summit. Choosing zero noise throughout creates a smooth geometric conical shape. There is a parameter CONVEX to control whether the basic conical structure bulges outwards or is pinched inwards in the middle. +meru 0.3.0 by paramat +For latest stable Minetest and compatible back to 0.4.8 +Depends default +License WTFPL diff --git a/init.lua b/init.lua index 8bd36f9..8941d98 100644 --- a/init.lua +++ b/init.lua @@ -1,128 +1,186 @@ --- meru 0.2.0 by paramat. --- License WTFPL. +-- meru 0.3.0 by paramat +-- For latest stable Minetest and compatible back to 0.4.8 +-- Depends default +-- License WTFPL --- Parameters. +-- Voxelmanip version -local ONGEN = true -- (true / false) Enable / disable generation. -local PROG = true -- Print processing progess to terminal. -local COORD = false -- Print tower co-ordinates to terminal. +-- Parameters -local XMIN = -1024 -- Area for random spawn. +local COORD = false -- Print tower co-ordinates to terminal (cheat) + +local XMIN = -1024 -- Area for random spawn local XMAX = 1024 local ZMIN = -1024 local ZMAX = 1024 -local BASRAD = 64 -- -- Average radius y = -32. -local HEIGHT = 1024 -- -- Approximate height measured from y = -32. -local CONVEX = 0.6 -- -- Convexity. 0.5 = concave, 1 = perfect cone, 2 = convex. -local VOID = 0.4 -- -- Void threshold. Controls size of central voids. -local NOISYRAD = 0.2 -- -- Noisyness of structure at base radius. 0 = smooth geometric form, 0.3 = noisy. -local NOISYCEN = 0 -- -- Noisyness of structure at centre. -local FISOFFBAS = 0.02 -- -- Fissure noise offset at base. controls amount / size of fissure entrances on outer surface. -local FISOFFTOP = 0.04 -- -- Fissure noise offset at top. -local FISEXPBAS = 0.6 -- -- Fissure expansion rate under surface at base. -local FISEXPTOP = 1.2 -- -- Fissure expansion rate under surface at top. +local BASRAD = 64 -- Average radius at y = -32 +local HEIGHT = 2048 -- Approximate height measured from y = -32 +local CONVEX = 0.6 -- Convexity. <1 = concave, 1 = conical, >1 = convex +local VOID = 0.4 -- Void threshold. Controls size of central void +local NOISYRAD = 0.2 -- Noisyness of structure at base radius. 0 = smooth geometric form, 0.3 = noisy +local NOISYCEN = 0 -- Noisyness of structure at centre +local FISOFFBAS = 0.02 -- Fissure noise offset at base. controls size of fissure entrances on outer surface +local FISOFFTOP = 0.04 -- Fissure noise offset at top +local FISEXPBAS = 0.6 -- Fissure expansion rate under surface at base +local FISEXPTOP = 1.2 -- Fissure expansion rate under surface at top -local SEEDDIFF1 = 46893 -- 3D noise for primary structure. -local OCTAVES1 = 5 -- -local PERSISTENCE1 = 0.5 -- -local SCALE1 = 64 -- +-- 3D noise for primary structure -local SEEDDIFF2 = 92940980987 -- 3D noise for fissures. -local OCTAVES2 = 4 -- -local PERSISTENCE2 = 0.5 -- -local SCALE2 = 24 -- +local np_structure = { + offset = 0, + scale = 1, + spread = {x=64, y=64, z=64}, + seed = 46893, + octaves = 5, + persist = 0.5 +} --- End of parameters. +-- 3D noise for fissures -meru = {} +local np_fissure = { + offset = 0, + scale = 1, + spread = {x=24, y=24, z=24}, + seed = 92940980987, + octaves = 4, + persist = 0.5 +} -local SEEDDIFF3 = 9130 -- 9130 -- Values should match minetest mapgen desert perlin. -local OCTAVES3 = 3 -- 3 -local PERSISTENCE3 = 0.5 -- 0.5 -local SCALE3 = 250 -- 250 +-- End of parameters -local SEEDDIFF4 = 5839090 -local OCTAVES4 = 2 -- 2 -local PERSISTENCE4 = 0.5 -- 0.5 -local SCALE4 = 3 -- 3 +-- 2D noise for biome. Parameters must match mgv6 biome noise -local cxmin = math.floor((XMIN + 32) / 80) -- chunk co ordinates +local np_biome = { + offset = 0, + scale = 1, + spread = {x=250, y=250, z=250}, + seed = 9130, + octaves = 3, + persist = 0.5 +} + +local cxmin = math.floor((XMIN + 32) / 80) -- limits in chunk co-ordinates local czmin = math.floor((ZMIN + 32) / 80) local cxmax = math.floor((XMAX + 32) / 80) local czmax = math.floor((ZMAX + 32) / 80) -local cxav = (cxmin + cxmax) / 2 +local cxav = (cxmin + cxmax) / 2 -- spawn area midpoint in chunk co-ordinates local czav = (czmin + czmax) / 2 -local xnom = (cxmax - cxmin) / 4 +local xnom = (cxmax - cxmin) / 4 -- noise multipliers local znom = (czmax - czmin) / 4 --- On generated function. +-- Nodes -if ONGEN then - minetest.register_on_generated(function(minp, maxp, seed) - if maxp.x >= XMIN and minp.x <= XMAX - and maxp.z >= ZMIN and minp.z <= ZMAX then - local env = minetest.env - local perlin4 = env:get_perlin(SEEDDIFF4, OCTAVES4, PERSISTENCE4, SCALE4) - local noisex = perlin4:get2d({x=31,y=23}) - local noisez = perlin4:get2d({x=17,y=11}) - local cx = cxav + math.floor(noisex * xnom) -- chunk co ordinates - local cz = czav + math.floor(noisez * znom) - local merux = 80 * cx + 8 - local meruz = 80 * cz + 8 - if COORD then - print ("[meru] x "..merux.." z "..meruz) - end - if minp.x >= merux - 120 and minp.x <= merux + 40 - and minp.z >= meruz - 120 and minp.z <= meruz + 40 - and minp.y >= -32 and minp.y <= HEIGHT * 1.2 then - local perlin1 = env:get_perlin(SEEDDIFF1, OCTAVES1, PERSISTENCE1, SCALE1) - local perlin2 = env:get_perlin(SEEDDIFF2, OCTAVES2, PERSISTENCE2, SCALE2) - local perlin3 = env:get_perlin(SEEDDIFF3, OCTAVES3, PERSISTENCE3, SCALE3) - local x1 = maxp.x - local y1 = maxp.y - local z1 = maxp.z - local x0 = minp.x - local y0 = minp.y - local z0 = minp.z - -- Loop through nodes in chunk. - for x = x0, x1 do - -- For each plane do. - if PROG then - print ("[meru] Plane "..x - x0.." Chunk ("..minp.x.." "..minp.y.." "..minp.z..")") - end - for z = z0, z1 do - -- For each column do. - local noise3 = perlin3:get2d({x=x+150,y=z+50}) -- Offsets must match minetest mapgen desert perlin. - local desert = false - if noise3 > 0.45 or math.random(0,10) > (0.45 - noise3) * 100 then -- Smooth transition 0.35 to 0.45. - desert = true - end - for y = y0, y1 do - -- For each node do. - local noise1 = perlin1:get3d({x=x,y=y,z=z}) - local radius = ((x - merux) ^ 2 + (z - meruz) ^ 2) ^ 0.5 - local deprop = (BASRAD - radius) / BASRAD - local noisy = NOISYRAD + deprop * (NOISYCEN - NOISYRAD) - local heprop = ((y + 32) / HEIGHT) - local offset = deprop - heprop ^ CONVEX - local noise1off = noise1 * noisy + offset - if noise1off > 0 and noise1off < VOID then - local noise2 = perlin2:get3d({x=x,y=y,z=z}) - local fisoff = FISOFFBAS + heprop * (FISOFFTOP - FISOFFBAS) - local fisexp = FISEXPBAS + heprop * (FISEXPTOP - FISEXPBAS) - if math.abs(noise2) - noise1off * fisexp - fisoff > 0 then - if desert then - env:add_node({x=x,y=y,z=z},{name="default:desert_stone"}) - else - env:add_node({x=x,y=y,z=z},{name="default:stone"}) - end - end - end +minetest.register_node("meru:stone", { + description = "Stone", + tiles = {"default_stone.png"}, + is_ground_content = false, + groups = {cracky=3, stone=1}, + drop = "default:cobble", + sounds = default.node_sound_stone_defaults(), +}) + +minetest.register_node("meru:destone", { + description = "Desert Stone", + tiles = {"default_desert_stone.png"}, + is_ground_content = false, + groups = {cracky=3, stone=1}, + drop = "default:desert_stone", + sounds = default.node_sound_stone_defaults(), +}) + +-- On generated function + +minetest.register_on_generated(function(minp, maxp, seed) + if maxp.x < XMIN or minp.x > XMAX + or maxp.z < ZMIN or minp.z > ZMAX then + return + end + + local locnoise = minetest.get_perlin(5839090, 2, 0.5, 3) + local noisex = locnoise:get2d({x=31,y=23}) + local noisez = locnoise:get2d({x=17,y=11}) + local cx = cxav + math.floor(noisex * xnom) -- chunk co ordinates + local cz = czav + math.floor(noisez * znom) + local merux = 80 * cx + 8 + local meruz = 80 * cz + 8 + if COORD then + print ("[meru] at x "..merux.." z "..meruz) + end + if minp.x < merux - 120 or minp.x > merux + 40 + or minp.z < meruz - 120 or minp.z > meruz + 40 + or minp.y < -32 or minp.y > HEIGHT * 1.2 then + return + end + + local t0 = os.clock() + local x0 = minp.x + local y0 = minp.y + local z0 = minp.z + local x1 = maxp.x + local y1 = maxp.y + local z1 = maxp.z + print ("[meru] chunk minp ("..x0.." "..y0.." "..z0..")") + + local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax} + local data = vm:get_data() + + local c_stone = minetest.get_content_id("meru:stone") + local c_destone = minetest.get_content_id("meru:destone") + + local sidelen = x1 - x0 + 1 + local chulens = {x=sidelen, y=sidelen, z=sidelen} + local minposxyz = {x=x0, y=y0, z=z0} + + local nvals_structure = minetest.get_perlin_map(np_structure, chulens):get3dMap_flat(minposxyz) + local nvals_fissure = minetest.get_perlin_map(np_fissure, chulens):get3dMap_flat(minposxyz) + local nvals_biome = minetest.get_perlin_map(np_biome, chulens):get2dMap_flat({x=x0+150, y=z0+50}) + + local nixyz = 1 -- 3D noise index + local nixz = 1 -- 2D noise index + for z = z0, z1 do + for y = y0, y1 do + local vi = area:index(x0, y, z) + for x = x0, x1 do + local n_structure = nvals_structure[nixyz] + local radius = ((x - merux) ^ 2 + (z - meruz) ^ 2) ^ 0.5 + local deprop = (BASRAD - radius) / BASRAD -- radial depth proportion + local noisy = NOISYRAD + deprop * (NOISYCEN - NOISYRAD) + local heprop = ((y + 32) / HEIGHT) -- height proportion + local offset = deprop - heprop ^ CONVEX + local n_offstructure = n_structure * noisy + offset + if n_offstructure > 0 and n_offstructure < VOID then + local n_absfissure = math.abs(nvals_fissure[nixyz]) + local fisoff = FISOFFBAS + heprop * (FISOFFTOP - FISOFFBAS) + local fisexp = FISEXPBAS + heprop * (FISEXPTOP - FISEXPBAS) + if n_absfissure - n_offstructure * fisexp - fisoff > 0 then + local n_biome = nvals_biome[nixz] + local desert = n_biome > 0.45 + or math.random(0,10) > (0.45 - n_biome) * 100 + if desert then + data[vi] = c_destone + else + data[vi] = c_stone end end end + + nixyz = nixyz + 1 + nixz = nixz + 1 + vi = vi + 1 end + nixz = nixz - sidelen end - end) -end + nixz = nixz + sidelen + end + + vm:set_data(data) + vm:set_lighting({day=0, night=0}) + vm:calc_lighting() + vm:write_to_map(data) + + local chugent = math.ceil((os.clock() - t0) * 1000) + print ("[meru] "..chugent.." ms") +end) +