532 lines
14 KiB
Lua
532 lines
14 KiB
Lua
local max_depth = 31000
|
|
local seed_noise = {offset = 0, scale = 32768, seed = 5202, spread = {x = 80, y = 80, z = 80}, octaves = 2, persist = 0.4, lacunarity = 2}
|
|
|
|
|
|
-- This tables looks up nodes that aren't already stored.
|
|
local node = setmetatable({}, {
|
|
__index = function(t, k)
|
|
if not (t and k and type(t) == 'table') then
|
|
return
|
|
end
|
|
|
|
t[k] = minetest.get_content_id(k)
|
|
return t[k]
|
|
end
|
|
})
|
|
|
|
local data = {}
|
|
local p2data = {} -- vm rotation data buffer
|
|
|
|
|
|
local biome_ids = {}
|
|
if fun_caves.use_bi_hi then
|
|
-- Create a table of biome ids, so I can use the biomemap.
|
|
local get_biome_id = minetest.get_biome_id
|
|
for name, desc in pairs(minetest.registered_biomes) do
|
|
biome_ids[get_biome_id(desc.name)] = desc.name
|
|
end
|
|
end
|
|
|
|
--local function get_decoration(biome)
|
|
-- for i, deco in pairs(fun_caves.decorations) do
|
|
-- if not deco.biomes or deco.biomes[biome] then
|
|
-- local range = 1000
|
|
-- if deco.deco_type == "simple" then
|
|
-- if deco.fill_ratio and math.random(range) - 1 < deco.fill_ratio * 1000 then
|
|
-- return deco.decoration
|
|
-- end
|
|
-- else
|
|
-- -- nop
|
|
-- end
|
|
-- end
|
|
-- end
|
|
--end
|
|
|
|
fun_caves.place_schematic = function(minp, maxp, data, p2data, area, node, pos, schem, center)
|
|
if not (minp and maxp and data and p2data and area and node and pos and schem and type(data) == 'table' and type(p2data) == 'table' and type(schem) == 'table') then
|
|
return
|
|
end
|
|
|
|
local rot = math.random(4) - 1
|
|
local yslice = {}
|
|
if schem.yslice_prob then
|
|
for _, ys in pairs(schem.yslice_prob) do
|
|
yslice[ys.ypos] = ys.prob
|
|
end
|
|
end
|
|
|
|
if center then
|
|
pos.x = pos.x - math.floor(schem.size.x / 2)
|
|
pos.z = pos.z - math.floor(schem.size.z / 2)
|
|
end
|
|
|
|
for z1 = 0, schem.size.z - 1 do
|
|
for x1 = 0, schem.size.x - 1 do
|
|
local x, z
|
|
if rot == 0 then
|
|
x, z = x1, z1
|
|
elseif rot == 1 then
|
|
x, z = schem.size.z - z1 - 1, x1
|
|
elseif rot == 2 then
|
|
x, z = schem.size.x - x1 - 1, schem.size.z - z1 - 1
|
|
elseif rot == 3 then
|
|
x, z = z1, schem.size.x - x1 - 1
|
|
end
|
|
local dz = pos.z - minp.z + z
|
|
local dx = pos.x - minp.x + x
|
|
if pos.x + x > minp.x and pos.x + x < maxp.x and pos.z + z > minp.z and pos.z + z < maxp.z then
|
|
local ivm = area:index(pos.x + x, pos.y, pos.z + z)
|
|
local isch = z1 * schem.size.y * schem.size.x + x1 + 1
|
|
local math_random = math.random
|
|
for y = 0, schem.size.y - 1 do
|
|
local dy = pos.y - minp.y + y
|
|
if yslice[y] or 255 >= math_random(255) then
|
|
local prob = schem.data[isch].prob or schem.data[isch].param1 or 255
|
|
if prob >= math_random(255) and schem.data[isch].name ~= "air" then
|
|
data[ivm] = node[schem.data[isch].name]
|
|
end
|
|
local param2 = schem.data[isch].param2 or 0
|
|
p2data[ivm] = param2
|
|
end
|
|
|
|
ivm = ivm + area.ystride
|
|
isch = isch + schem.size.x
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
fun_caves.surround = function(node, data, area, ivm)
|
|
if not (node and data and area and ivm and type(data) == 'table' and type(ivm) == 'number') then
|
|
return
|
|
end
|
|
|
|
-- Check to make sure that a plant root is fully surrounded.
|
|
-- This is due to the kludgy way you have to make water plants
|
|
-- in minetest, to avoid bubbles.
|
|
for x1 = -1,1,2 do
|
|
local n = data[ivm+x1]
|
|
if n == node["default:river_water_source"] or n == node["default:water_source"] or n == node["air"] then
|
|
return false
|
|
end
|
|
end
|
|
for z1 = -area.zstride,area.zstride,2*area.zstride do
|
|
local n = data[ivm+z1]
|
|
if n == node["default:river_water_source"] or n == node["default:water_source"] or n == node["air"] then
|
|
return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
|
|
fun_caves.underzones = {
|
|
Caina = {
|
|
name = 'Caina',
|
|
ceiling = -4852,
|
|
ceiling_node = 'default:ice',
|
|
column_node = 'default:ice',
|
|
column_node_rare = 'fun_caves:thin_ice',
|
|
floor = -4972,
|
|
floor_node = 'default:ice',
|
|
lower_bound = -4992,
|
|
regular_columns = false,
|
|
stalactite = 'fun_caves:icicle_down',
|
|
stalactite_chance = 12,
|
|
stone_depth = 2,
|
|
upper_bound = -4832,
|
|
vary = true,
|
|
},
|
|
Phlegethos = {
|
|
name = 'Phlegethos',
|
|
ceiling = -9892,
|
|
ceiling_node = 'fun_caves:black_sand',
|
|
column_node = 'default:stone',
|
|
column_node_rare = 'fun_caves:hot_stone',
|
|
floor = -10012,
|
|
floor_node = 'fun_caves:hot_cobble',
|
|
fluid = 'default:lava_source',
|
|
fluid_chance = 1200,
|
|
lake = 'default:lava_source',
|
|
lake_level = 5,
|
|
lower_bound = -10032,
|
|
regular_columns = false,
|
|
stone_depth = 1,
|
|
upper_bound = -9872,
|
|
vary = true,
|
|
},
|
|
Dis = {
|
|
name = 'Dis',
|
|
ceiling = -14914,
|
|
ceiling_node = 'fun_caves:hot_brass',
|
|
column_node = 'default:steelblock',
|
|
floor = -14982,
|
|
floor_node = 'fun_caves:hot_brass',
|
|
lower_bound = -14992,
|
|
regular_columns = true,
|
|
stone_depth = 1,
|
|
upper_bound = -14912,
|
|
vary = false,
|
|
},
|
|
Minauros = {
|
|
name = 'Minauros',
|
|
ceiling = -19812,
|
|
ceiling_node = 'fun_caves:black_sand',
|
|
column_node = 'fun_caves:polluted_dirt',
|
|
column_node_rare = 'fun_caves:glowing_fungal_stone',
|
|
floor = -19932,
|
|
floor_node = 'fun_caves:polluted_dirt',
|
|
fluid = 'fun_caves:water_poison_source',
|
|
fluid_chance = 2000,
|
|
lake = 'fun_caves:water_poison_source',
|
|
lake_level = 10,
|
|
lower_bound = -19952,
|
|
regular_columns = false,
|
|
stone_depth = 2,
|
|
upper_bound = -19792,
|
|
vary = true,
|
|
},
|
|
Styx = {
|
|
name = 'Styx',
|
|
ceiling = -29812,
|
|
ceiling_node = 'default:dirt',
|
|
floor = -30012,
|
|
floor_node = 'default:dirt',
|
|
lower_bound = -30032,
|
|
regular_columns = false,
|
|
stone_depth = 2,
|
|
sealevel = -29842,
|
|
upper_bound = -29792,
|
|
vary = true,
|
|
},
|
|
}
|
|
|
|
fun_caves.cave_biomes = {
|
|
algae = {
|
|
biome_val_low = 0,
|
|
biome_val_high = 0.2,
|
|
ceiling_node = 'fun_caves:stone_with_algae',
|
|
dirt = 'default:dirt',
|
|
dirt_chance = 10,
|
|
floor_node = 'fun_caves:stone_with_algae',
|
|
fungi = true,
|
|
stalactite = 'fun_caves:stalactite_slimy',
|
|
stalactite_chance = 12,
|
|
stalagmite = 'fun_caves:stalagmite_slimy',
|
|
stalagmite_chance = 12,
|
|
stone_depth = 1,
|
|
underwater = true,
|
|
},
|
|
coal = {
|
|
biome_val_low = 0.5,
|
|
biome_val_high = 0.6,
|
|
ceiling_node = 'fun_caves:black_sand',
|
|
deco = 'default:coalblock',
|
|
deco_chance = 100,
|
|
floor_node = 'fun_caves:black_sand',
|
|
stalagmite = 'fun_caves:constant_flame',
|
|
stalagmite_chance = 50,
|
|
stone_depth = 2,
|
|
underwater = false,
|
|
},
|
|
hot = {
|
|
biome_val_low = 0.6,
|
|
biome_val_high = 99,
|
|
ceiling_node = 'fun_caves:hot_cobble',
|
|
floor_node = 'fun_caves:hot_cobble',
|
|
fluid = 'default:lava_source',
|
|
fluid_chance = 300,
|
|
stalagmite = fun_caves.hot_spikes,
|
|
stalagmite_chance = 50,
|
|
stone_depth = 1,
|
|
underwater = false,
|
|
},
|
|
ice = {
|
|
biome_val_low = -99,
|
|
biome_val_high = -0.6,
|
|
ceiling_node = 'default:ice',
|
|
floor_node = 'default:ice',
|
|
stalactite = 'fun_caves:icicle_down',
|
|
stalactite_chance = 12,
|
|
stalagmite = 'fun_caves:icicle_up',
|
|
stalagmite_chance = 12,
|
|
stone_depth = 2,
|
|
underwater = true,
|
|
},
|
|
ice_thin = {
|
|
biome_val_low = -0.6,
|
|
biome_val_high = -0.5,
|
|
ceiling_node = 'fun_caves:thin_ice',
|
|
floor_node = 'fun_caves:thin_ice',
|
|
stone_depth = 2,
|
|
underwater = true,
|
|
},
|
|
lichen = {
|
|
biome_val_low = -0.3,
|
|
biome_val_high = 0,
|
|
ceiling_node = 'fun_caves:stone_with_lichen',
|
|
dirt = 'default:dirt',
|
|
dirt_chance = 10,
|
|
floor_node = 'fun_caves:stone_with_lichen',
|
|
fungi = true,
|
|
stalactite = 'fun_caves:stalactite',
|
|
stalactite_chance = 12,
|
|
stalagmite = 'fun_caves:stalagmite',
|
|
stalagmite_chance = 12,
|
|
stone_depth = 1,
|
|
underwater = true,
|
|
},
|
|
lichen_dead = {
|
|
biome_val_low = -0.6,
|
|
biome_val_high = -0.5,
|
|
ceiling_node = 'fun_caves:stone_with_lichen',
|
|
floor_node = 'fun_caves:stone_with_lichen',
|
|
stalactite = 'fun_caves:stalactite',
|
|
stalactite_chance = 12,
|
|
stalagmite = 'fun_caves:stalagmite',
|
|
stalagmite_chance = 12,
|
|
stone_depth = 1,
|
|
underwater = true,
|
|
},
|
|
moss = {
|
|
biome_val_low = -0.5,
|
|
biome_val_high = -0.3,
|
|
ceiling_node = 'fun_caves:stone_with_moss',
|
|
deco = 'fun_caves:glowing_fungal_stone',
|
|
deco_chance = 50,
|
|
floor_node = 'fun_caves:stone_with_moss',
|
|
fluid = 'default:water_source',
|
|
fluid_chance = 300,
|
|
stalactite = 'fun_caves:stalactite_mossy',
|
|
stalactite_chance = 12,
|
|
stalagmite = 'fun_caves:stalagmite_mossy',
|
|
stalagmite_chance = 12,
|
|
stone_depth = 1,
|
|
underwater = true,
|
|
},
|
|
salt = {
|
|
biome_val_low = 0.2,
|
|
biome_val_high = 0.35,
|
|
ceiling_node = 'fun_caves:stone_with_salt',
|
|
deco = 'fun_caves:radioactive_ore',
|
|
deco_chance = 500,
|
|
floor_node = 'fun_caves:stone_with_salt',
|
|
stone_depth = 2,
|
|
underwater = false,
|
|
},
|
|
sand = {
|
|
biome_val_low = 0.35,
|
|
biome_val_high = 0.5,
|
|
ceiling_node = 'default:sand',
|
|
floor_node = 'default:sand',
|
|
stone_depth = 2,
|
|
underwater = true,
|
|
},
|
|
}
|
|
|
|
|
|
local ground_nodes = {}
|
|
ground_nodes[minetest.get_content_id('default:stone')] = true
|
|
ground_nodes[minetest.get_content_id('default:desert_stone')] = true
|
|
ground_nodes[minetest.get_content_id('default:sandstone')] = true
|
|
ground_nodes[minetest.get_content_id('default:dirt')] = true
|
|
ground_nodes[minetest.get_content_id('default:sand')] = true
|
|
ground_nodes[minetest.get_content_id('default:dirt_with_grass')] = true
|
|
ground_nodes[minetest.get_content_id('default:dirt_with_snow')] = true
|
|
ground_nodes[minetest.get_content_id('default:dirt_with_dry_grass')] = true
|
|
|
|
|
|
local function generate(p_minp, p_maxp, seed)
|
|
if not (p_minp and p_maxp and seed) then
|
|
return
|
|
end
|
|
|
|
local minp, maxp = p_minp, p_maxp
|
|
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
|
if not (vm and emin and emax) then
|
|
return
|
|
end
|
|
|
|
vm:get_data(data)
|
|
p2data = vm:get_param2_data()
|
|
local heightmap
|
|
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
|
local csize = vector.add(vector.subtract(maxp, minp), 1)
|
|
|
|
if fun_caves.use_bi_hi then
|
|
heightmap = minetest.get_mapgen_object("heightmap")
|
|
end
|
|
|
|
-- use the same seed (based on perlin noise).
|
|
do
|
|
local seed = minetest.get_perlin(seed_noise):get2d({x=minp.x, y=minp.z})
|
|
if not (seed and type(seed) == 'number') then
|
|
return
|
|
end
|
|
|
|
math.randomseed(seed)
|
|
end
|
|
|
|
local write = false
|
|
local write_p2, write_p4 = false, false
|
|
local underzone
|
|
if not fun_caves.underzones then
|
|
return
|
|
end
|
|
|
|
for _, uz in pairs(fun_caves.underzones) do
|
|
local avg = (minp.y + maxp.y) / 2
|
|
if avg <= uz.upper_bound and avg >= uz.lower_bound then
|
|
underzone = uz
|
|
end
|
|
end
|
|
|
|
-- Correct heightmap.
|
|
local index = 0
|
|
for z = minp.z, maxp.z do
|
|
for x = minp.x, maxp.x do
|
|
index = index + 1
|
|
|
|
local height = heightmap[index]
|
|
if height and height < maxp.y - 1 and height > minp.y then
|
|
--nop
|
|
else
|
|
height = - max_depth
|
|
local ivm2 = area:index(x, maxp.y + 8, z)
|
|
for y = maxp.y + 8, minp.y - 8, -1 do
|
|
if ground_nodes[data[ivm2]] then
|
|
height = (y < maxp.y + 8) and y or max_depth
|
|
break
|
|
end
|
|
ivm2 = ivm2 - area.ystride
|
|
end
|
|
heightmap[index] = height
|
|
end
|
|
end
|
|
end
|
|
|
|
local aster = false
|
|
for fake_loop = 1, 1 do
|
|
if minp.y > 17200 then
|
|
break
|
|
end
|
|
|
|
if minp.y > 11000 and fun_caves.asteroids then
|
|
write = fun_caves.asteroids(minp, maxp, data, p2data, area, node)
|
|
aster = true
|
|
break
|
|
end
|
|
|
|
if minp.y > 8400 and fun_caves.skysea then
|
|
write = fun_caves.skysea(minp, maxp, data, p2data, area, node)
|
|
break
|
|
end
|
|
|
|
if minp.y > 4000 and fun_caves.cloudgen then
|
|
write = fun_caves.cloudgen(minp, maxp, data, p2data, area, node)
|
|
break
|
|
end
|
|
|
|
if fun_caves.dungeon then
|
|
write, write_p2 = fun_caves.dungeon(minp, maxp, data, p2data, area, node, heightmap)
|
|
if write then
|
|
break
|
|
end
|
|
end
|
|
|
|
if fun_caves.cavegen and fun_caves.decogen then
|
|
local h2
|
|
write, h2 = fun_caves.cavegen(minp, maxp, data, area, node, heightmap, underzone, ground_nodes)
|
|
if h2 then
|
|
heightmap = h2
|
|
end
|
|
|
|
local biomemap
|
|
if fun_caves.use_bi_hi then
|
|
biomemap = minetest.get_mapgen_object("biomemap")
|
|
end
|
|
|
|
local write_deco
|
|
write_deco, write_p2 = fun_caves.decogen(minp, maxp, data, p2data, area, node, heightmap, biomemap, biome_ids, underzone)
|
|
write = write or write_deco
|
|
|
|
if fun_caves.treegen then
|
|
local write_tree = fun_caves.treegen(minp, maxp, data, p2data, area, node)
|
|
if write_tree then
|
|
write = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if fun_caves.pyramid then
|
|
local write_pyr, write_p4 = fun_caves.pyramid(minp, maxp, data, p2data, area, biomemap, biome_ids, node, heightmap)
|
|
if write_pyr then
|
|
write = true
|
|
write_p2 = write_p2 or write_p4
|
|
break
|
|
end
|
|
end
|
|
|
|
if fun_caves.use_villages and biomemap and fun_caves.village then
|
|
local biome = biome_ids[biomemap[40*80+40]]
|
|
local write_vill = fun_caves.village(minp, maxp, data, p2data, area, node, biome, heightmap)
|
|
if write_vill then
|
|
write = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
if write then
|
|
vm:set_data(data)
|
|
if write_p2 or write_p4 then
|
|
vm:set_param2_data(p2data)
|
|
end
|
|
|
|
if fun_caves.DEBUG then
|
|
vm:set_lighting({day = 15, night = 15})
|
|
else
|
|
-- set_lighting causes lighting artifacts,
|
|
-- but corrects the light inside trees.
|
|
vm:set_lighting({day = 0, night = 0}, minp, maxp)
|
|
vm:calc_lighting(minp, maxp, not aster)
|
|
-- Does not work:
|
|
--vm:calc_lighting({x=minp.x,y=emin.y,z=minp.z}, maxp)
|
|
end
|
|
vm:update_liquids()
|
|
vm:write_to_map()
|
|
end
|
|
end
|
|
|
|
|
|
if fun_caves.path then
|
|
dofile(fun_caves.path .. "/asteroids.lua")
|
|
dofile(fun_caves.path .. "/cavegen.lua")
|
|
dofile(fun_caves.path .. "/cloudgen.lua")
|
|
dofile(fun_caves.path .. "/decogen.lua")
|
|
dofile(fun_caves.path .. "/dungeon.lua")
|
|
dofile(fun_caves.path .. "/pyramid.lua")
|
|
dofile(fun_caves.path .. "/treegen.lua")
|
|
dofile(fun_caves.path .. "/village.lua")
|
|
dofile(fun_caves.path .. "/skyseagen.lua")
|
|
end
|
|
|
|
|
|
local function pgenerate(...)
|
|
--local status, err = pcall(generate, ...)
|
|
local status, err = true
|
|
generate(...)
|
|
if not status then
|
|
print('Fun Caves: Could not generate terrain:')
|
|
print(dump(err))
|
|
collectgarbage("collect")
|
|
end
|
|
end
|
|
|
|
|
|
-- Inserting helps to ensure that fun_caves operates first.
|
|
table.insert(minetest.registered_on_generateds, 1, pgenerate)
|