123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557 |
- -- Caverealm noise, choses when cave biomes can spawn and what is left stone.
- local noise1param3d = {
- offset = 0,
- scale = 1,
- spread = {x=128, y=128, z=128},
- seed = 708291,
- octaves = 6,
- persist = 0.7,
- lacunarity = 2
- }
- -- Vein noise. Choses size & frequency of floor or roof ore veins.
- local noise2param3d = {
- offset = 0,
- scale = 1,
- spread = {x=128, y=128, z=128},
- seed = 48791,
- octaves = 4,
- persist = 0.5,
- lacunarity = 2
- }
- -- Biome noise, used to chose what cave biome should generate.
- local noise3param3d = {
- offset = 0,
- scale = 1,
- spread = {x=512, y=512, z=512},
- seed = 127726,
- octaves = 4,
- persist = 0.7,
- lacunarity = 2
- }
- -- Content-IDs for the voxel manipulator.
- local c_air = minetest.get_content_id("air")
- local c_stone = minetest.get_content_id("default:stone")
- local c_cobble = minetest.get_content_id("cavestuff:cobble") -- Special nodetype.
- local c_mossy_cobble = minetest.get_content_id("default:mossycobble")
- local c_cobble_moss = minetest.get_content_id("cavestuff:cobble_with_moss")
- local c_cobble_lichen = minetest.get_content_id("cavestuff:cobble_with_lichen")
- local c_cobble_algae = minetest.get_content_id("cavestuff:cobble_with_algae")
- local c_cobble_salt = minetest.get_content_id("cavestuff:cobble_with_salt")
- local c_coal_block = minetest.get_content_id("default:coalblock")
- local c_quartz_block = minetest.get_content_id("quartz:block")
- local c_dark_obsidian = minetest.get_content_id("cavestuff:dark_obsidian")
- local c_thin_ice = minetest.get_content_id("ice:thin_ice")
- local c_ice = minetest.get_content_id("default:ice")
- local c_sandy_ice = minetest.get_content_id("sand:sand_with_ice_crystals")
- -- These tables are updated per chunk-generation iteration.
- -- Keeping them external improves performance according to MT Lua docs.
- local data = {} -- Voxelmanip data table external for performance.
- local noisemap1 = {}
- local noisemap2 = {}
- local noisemap3 = {}
- -- Mapgen notes: this algorithm does not create any caves. It populates caves
- -- already generated by the C++ mapgen. Use huge Valleys caves for best results.
- cavegen.generate = function(minp, maxp, seed)
- -- Do not run for chunks above or below the caverealm region.
- if minp.y > -5000 or maxp.y < -23000 then
- return
- end
-
- -- Grab the voxel manipulator.
- local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
- vm:get_data(data)
- local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
- local area2 = VoxelArea:new{MinEdge=minp, MaxEdge=maxp} -- Noise area.
-
- local pr = PseudoRandom(seed + 71)
-
- 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 bp3d = {x=x0, y=y0, z=z0}
-
- local perlin1 = minetest.get_perlin_map(noise1param3d, sides3D)
- perlin1:get_3d_map_flat(bp3d, noisemap1)
-
- local perlin2 = minetest.get_perlin_map(noise2param3d, sides3D)
- perlin2:get_3d_map_flat(bp3d, noisemap2)
-
- local perlin3 = minetest.get_perlin_map(noise3param3d, sides3D)
- perlin3:get_3d_map_flat(bp3d, noisemap3)
-
- local floor = math.floor
- local ceil = math.ceil
- local abs = math.abs
- local clamp = function(v, l, u)
- if v < l then return l end
- if v > u then return u end
- return v
- end
-
- -- Compute caverealm threshold. 0 = no caverealm, 1 = max possible.
- local compute_threshold = function(y)
- -- Height values outside outer range result in 0.
- if y > -5000 then
- return 0
- elseif y > -17000 then
- -- Y is below -5k and above -10k. Need fade!
- local a = (y+5000)/12000 -- Get value between 1 and 0.
- return abs(a)
- elseif y > -22000 then
- return 1
- elseif y > -23000 then
- -- Y is below -22k and above -23k. Need fade!
- local a = (y+23000)/1000 -- Get value between 1 and 0.
- return a
- else
- return 0
- end
- end
-
- -- These tables will be filled with locations for decorations,
- -- calculated by the voxel manipulator code. After the voxel manipulator
- -- runs, decorations should be placed at locations in these tables.
- local glowstrings = {}
- local rooficicles = {}
- local floorcicles = {}
- local mycenashrom = {}
- local fungusshrom = {}
- local cavespikeps = {}
- local saltcrystal = {}
- local moongemspos = {}
- local sapphrspike = {} -- Sapphire spikes.
- local emraldspike = {} -- Emerald spikes.
- local emraldspik2 = {} -- Emerald spikes.
- local rubyspikes1 = {}
- local amethystspk = {}
- local mesespikes1 = {}
- local swaterwells = {}
-
- for z = z0, z1 do
- for x = x0, x1 do
- for y = y0, y1 do
- -- Get index into 3D noise array.
- local ni3 = area2:index(x, y, z)
-
- local n1 = noisemap1[ni3]
- local n2 = noisemap2[ni3]
- local n3 = noisemap3[ni3]
-
- local threshold = compute_threshold(y)
- local rn = clamp(abs(n1), 0, 1) -- Caverealm noise.
-
- if rn <= threshold then
- 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]
-
- -- If found cave ceiling.
- if ip == c_stone and id == c_air then
- data[vp] = c_cobble -- Plain cobble on roof.
- if abs(n2) < 0.04 then
- data[vd] = c_quartz_block
- elseif abs(n2) < 0.09 then
- data[vd] = c_coal_block
- elseif pr:next(1, 100) == 1 then -- Glow worms.
- glowstrings[#glowstrings+1] = {x=x, y=y-1, z=z}
- elseif pr:next(1, 100) == 1 then -- Icicles
- rooficicles[#rooficicles+1] = {x=x, y=y-1, z=z}
- data[vp] = c_thin_ice -- Override cobble roof.
- end
- end
-
- if rn <= threshold*0.8 then
- -- If found raw cave floor.
- -- We check floor after ceiling in case floor and ceiling
- -- intersect. This way, floor material takes precedence.
- if ip == c_stone and iu == c_air then
- data[vp] = c_cobble -- Plain cobble under floor surface.
- if abs(n2) < 0.05 then
- data[vu] = c_dark_obsidian
- else
- -- Chose floor type to place. Floor type determines biome.
- local bn = abs(n3)
- if bn < 0.1 then
- data[vu] = c_cobble_moss
- elseif bn < 0.3 then
- data[vu] = c_cobble_algae
- elseif bn < 0.6 then
- data[vu] = c_cobble_lichen
- elseif bn < 0.8 then
- data[vu] = c_cobble_salt
- elseif bn < 0.9 then
- data[vu] = c_sandy_ice
- else
- data[vu] = c_thin_ice
- if bn > 1.0 then
- data[vp] = c_ice -- Override cobble floor.
- end
- end
- end
- end
- end
-
- -- Floor & roof types have changed, re-read them.
- ip = data[vp]
- iu = data[vu]
- id = data[vd]
-
- -- If found generated ice cave floor.
- -- Generate position tables for ice biome decorations.
- if ip == c_thin_ice and iu == c_air then
- if pr:next(1, 100) == 1 then
- floorcicles[#floorcicles+1] = {x=x, y=y+1, z=z}
- data[vp] = c_ice
- end
- end
-
- -- If found floor of biome suitable for mushrooms.
- -- Generate position tables for mushrooms.
- if (ip == c_cobble_moss or
- ip == c_cobble_algae or
- ip == c_cobble_lichen) and iu == c_air then
- if pr:next(1, 100) == 1 then
- mycenashrom[#mycenashrom+1] = {x=x, y=y+1, z=z}
- data[vp] = c_mossy_cobble
- elseif pr:next(1, 70) == 1 then
- fungusshrom[#fungusshrom+1] = {x=x, y=y+1, z=z}
- data[vp] = c_mossy_cobble
- end
- end
-
- if ip == c_cobble_salt and iu == c_air then
- if pr:next(1, 100) == 1 then
- saltcrystal[#saltcrystal+1] = {x=x, y=y+1, z=z}
- end
- end
-
- if ip == c_cobble_lichen and iu == c_air then
- if pr:next(1, 200) == 1 then
- moongemspos[#moongemspos+1] = {x=x, y=y+1, z=z}
- end
- end
-
- -- Water wells.
- if pr:next(1, 40) == 1 then
- if iu == c_air and ip == c_cobble_moss then
- swaterwells[#swaterwells+1] = {x=x, y=y, z=z}
- end
- end
-
- -- Chance for spikes is deceptively high.
- -- Most of these locations will be rejected due to ground checks later.
- if pr:next(1, 40) == 1 then
- if iu == c_air then
- if ip == c_cobble_lichen then
- sapphrspike[#sapphrspike+1] = {x=x, y=y+1, z=z}
- end
-
- if ip == c_cobble_moss then
- emraldspike[#emraldspike+1] = {x=x, y=y+1, z=z}
- end
-
- if ip == c_cobble_algae then
- emraldspik2[#emraldspik2+1] = {x=x, y=y+1, z=z}
- end
- end
-
- -- Ceiling spikes.
- if ip == c_cobble and id == c_air then
- local which = pr:next(1, 3)
- if which == 1 then
- mesespikes1[#mesespikes1+1] = {x=x, y=y-1, z=z}
- elseif which == 2 then
- rubyspikes1[#rubyspikes1+1] = {x=x, y=y-1, z=z}
- elseif which == 3 then
- amethystspk[#amethystspk+1] = {x=x, y=y-1, z=z}
- end
- end
- end
-
- -- If found raw stone floor (edges of caverealm biomes).
- -- Generate positions for rock spikes.
- if ip == c_stone and iu == c_air then
- if pr:next(1, 40) == 1 then
- cavespikeps[#cavespikeps+1] = {x=x, y=y+1, z=z}
- end
- end
- end
- end -- For all in Y coordinates.
- end -- For all in X coordinates.
- end -- For all in Z coordinates.
-
- -- Finalize voxel manipulator.
- vm:set_data(data)
- vm:set_lighting({day=0, night=0})
- vm:calc_lighting()
- vm:update_liquids()
- vm:write_to_map()
-
- -- Place glow worms.
- -- Glow worms come in columns of nodes,
- -- so this needs a special algorithm.
- for k, v in ipairs(glowstrings) do
- local len = pr:next(1, pr:next(2, 5))
- for i=0, len, 1 do
- local pos = {x=v.x, y=v.y-i, z=v.z}
- if minetest.get_node(pos).name == "air" then
- minetest.set_node(pos, {name="cavestuff:glow_worm"})
- else
- break
- end
- end
- end
-
- -- Function for quickly placing 1-node sized decorations.
- local place_decorations = function(nn, tt)
- for k, v in ipairs(tt) do
- local pos = {x=v.x, y=v.y, z=v.z}
- if minetest.get_node(pos).name == "air" then
- minetest.set_node(pos, {name=nn})
- end
- end
- end
-
- place_decorations("cavestuff:icicle_down", rooficicles)
- place_decorations("cavestuff:icicle_up", floorcicles)
- place_decorations("cavestuff:mycena", mycenashrom)
- place_decorations("cavestuff:fungus", fungusshrom)
-
- -- Place stone spikes.
- for k, v in ipairs(cavespikeps) do
- local pos = {x=v.x, y=v.y, z=v.z}
- if minetest.get_node(pos).name == "air" then
- minetest.set_node(pos, {name="cavestuff:spike" .. pr:next(1, 4)})
- end
- end
-
- -- Place salt crystals.
- for k, v in ipairs(saltcrystal) do
- local pos = {x=v.x, y=v.y, z=v.z}
- if minetest.get_node(pos).name == "air" then
- minetest.set_node(pos, {name="cavestuff:saltcrystal" .. pr:next(1, 4)})
- end
- end
-
- -- Place moon gems.
- for k, v in ipairs(moongemspos) do
- local pos = {x=v.x, y=v.y, z=v.z}
- if minetest.get_node(pos).name == "air" then
- minetest.set_node(pos, {name="cavestuff:bluecrystal" .. pr:next(1, 4)})
- end
- end
-
- local place_spike_up = function(gname, basename, spikename, postable)
- for k, v in ipairs(postable) do
- -- Check foundation to see if a spike can be placed here.
- local floorcheck = {
- {x=v.x, y=v.y-1, z=v.z},
- {x=v.x-1, y=v.y-1, z=v.z},
- {x=v.x+1, y=v.y-1, z=v.z},
- {x=v.x, y=v.y-1, z=v.z-1},
- {x=v.x, y=v.y-1, z=v.z+1},
- }
- for i, j in ipairs(floorcheck) do
- if minetest.get_node(j).name ~= gname then
- return -- Bad foundation.
- end
- end
-
- -- Foundation is solid.
- -- Build crystaline base.
- local crystalbase = {
- {x=v.x, y=v.y, z=v.z},
-
- {x=v.x-1, y=v.y, z=v.z},
- {x=v.x+1, y=v.y, z=v.z},
- {x=v.x, y=v.y, z=v.z-1},
- {x=v.x, y=v.y, z=v.z+1},
-
- {x=v.x-1, y=v.y, z=v.z-1},
- {x=v.x+1, y=v.y, z=v.z-1},
- {x=v.x-1, y=v.y, z=v.z+1},
- {x=v.x+1, y=v.y, z=v.z+1},
-
- {x=v.x-2, y=v.y, z=v.z},
- {x=v.x+2, y=v.y, z=v.z},
- {x=v.x, y=v.y, z=v.z-2},
- {x=v.x, y=v.y, z=v.z+2},
- }
- for i, j in ipairs(crystalbase) do
- minetest.set_node(j, {name=basename})
- end
-
- -- Build upwards pointing spike.
- local l = pr:next(7, 20)
- local l1 = pr:next(floor(l/3), floor((l/3)*2))
- local l2 = pr:next(floor(l/3), floor((l/3)*2))
- local l3 = pr:next(floor(l/3), floor((l/3)*2))
- local l4 = pr:next(floor(l/3), floor((l/3)*2))
-
- local buildspike = function(pos, len)
- for i=0, len, 1 do
- local p = {x=pos.x, y=pos.y+i, z=pos.z}
- -- Spikes grow through everything,
- -- but quit if at unloaded chunk border.
- if minetest.get_node(p).name == "ignore" then return end
- minetest.set_node(p, {name=spikename})
- end
- end
-
- buildspike({x=v.x, y=v.y+1, z=v.z}, l)
- buildspike({x=v.x-1, y=v.y+1, z=v.z}, l1)
- buildspike({x=v.x+1, y=v.y+1, z=v.z}, l2)
- buildspike({x=v.x, y=v.y+1, z=v.z-1}, l3)
- buildspike({x=v.x, y=v.y+1, z=v.z+1}, l4)
- end
- end
-
- local place_spike_down = function(gname, basename, spikename, postable)
- for k, v in ipairs(postable) do
- -- Check foundation to see if a spike can be placed here.
- local floorcheck = {
- {x=v.x, y=v.y+1, z=v.z},
- {x=v.x-1, y=v.y+1, z=v.z},
- {x=v.x+1, y=v.y+1, z=v.z},
- {x=v.x, y=v.y+1, z=v.z-1},
- {x=v.x, y=v.y+1, z=v.z+1},
- }
- for i, j in ipairs(floorcheck) do
- if minetest.get_node(j).name ~= gname then
- return -- Bad foundation.
- end
- end
-
- -- Foundation is solid.
- -- Build crystaline base.
- local crystalbase = {
- {x=v.x, y=v.y, z=v.z},
-
- {x=v.x-1, y=v.y, z=v.z},
- {x=v.x+1, y=v.y, z=v.z},
- {x=v.x, y=v.y, z=v.z-1},
- {x=v.x, y=v.y, z=v.z+1},
-
- {x=v.x-1, y=v.y, z=v.z-1},
- {x=v.x+1, y=v.y, z=v.z-1},
- {x=v.x-1, y=v.y, z=v.z+1},
- {x=v.x+1, y=v.y, z=v.z+1},
-
- {x=v.x-2, y=v.y, z=v.z},
- {x=v.x+2, y=v.y, z=v.z},
- {x=v.x, y=v.y, z=v.z-2},
- {x=v.x, y=v.y, z=v.z+2},
- }
- for i, j in ipairs(crystalbase) do
- minetest.set_node(j, {name=basename})
- end
-
- -- Build downwards pointing spike.
- local l = pr:next(7, 20)
- local l1 = pr:next(floor(l/3), floor((l/3)*2))
- local l2 = pr:next(floor(l/3), floor((l/3)*2))
- local l3 = pr:next(floor(l/3), floor((l/3)*2))
- local l4 = pr:next(floor(l/3), floor((l/3)*2))
-
- local buildspike = function(pos, len)
- for i=0, len, 1 do
- local p = {x=pos.x, y=pos.y-i, z=pos.z}
- -- Spikes grow through everything,
- -- but quit if at unloaded chunk border.
- if minetest.get_node(p).name == "ignore" then return end
- minetest.set_node(p, {name=spikename})
- end
- end
-
- buildspike({x=v.x, y=v.y-1, z=v.z}, l)
- buildspike({x=v.x-1, y=v.y-1, z=v.z}, l1)
- buildspike({x=v.x+1, y=v.y-1, z=v.z}, l2)
- buildspike({x=v.x, y=v.y-1, z=v.z-1}, l3)
- buildspike({x=v.x, y=v.y-1, z=v.z+1}, l4)
- end
- end
-
- local place_water_well = function(gname, postable)
- for k, v in ipairs(postable) do
- -- Check foundation to see if a spike can be placed here.
- local floorcheck = {
- {x=v.x, y=v.y, z=v.z},
- {x=v.x-1, y=v.y, z=v.z},
- {x=v.x+1, y=v.y, z=v.z},
- {x=v.x, y=v.y, z=v.z-1},
- {x=v.x, y=v.y, z=v.z+1},
- }
- for i, j in ipairs(floorcheck) do
- if minetest.get_node(j).name ~= gname then
- return -- Bad foundation.
- end
- end
-
- local offset = vector.new(-2, 0, -2)
- local pos = vector.add(v, offset)
-
- local path = cavegen.modpath .. "/caverealm_freshwater_well.mts"
- minetest.place_schematic(pos, path, "random", nil, true)
- end
- end
-
- place_spike_up(
- "cavestuff:cobble_with_lichen",
- "cavestuff:glow_sapphire_ore",
- "cavestuff:glow_sapphire",
- sapphrspike)
-
- place_spike_up(
- "cavestuff:cobble_with_moss",
- "cavestuff:glow_emerald_ore",
- "cavestuff:glow_emerald",
- emraldspike)
-
- place_spike_up(
- "cavestuff:cobble_with_algae",
- "cavestuff:glow_emerald_ore",
- "cavestuff:glow_emerald",
- emraldspik2)
-
- place_spike_down(
- "cavestuff:cobble",
- "cavestuff:glow_ruby_ore",
- "cavestuff:glow_ruby",
- rubyspikes1)
-
- place_spike_down(
- "cavestuff:cobble",
- "cavestuff:glow_amethyst_ore",
- "cavestuff:glow_amethyst",
- amethystspk)
-
- place_spike_down(
- "cavestuff:cobble",
- "default:stone_with_mese",
- "cavestuff:glow_mese",
- mesespikes1)
-
- place_water_well(
- "cavestuff:cobble_with_moss",
- swaterwells)
- end
|