catacomb/init.lua

1015 lines
31 KiB
Lua

-- Parameters
-- Approximate generation limits
local YMIN = -33000
local YMAX = 33000
local XMIN = -33000
local XMAX = 33000
local ZMIN = -33000
local ZMAX = 33000
local YMAXSPA = -33 -- Maximum y for initial catacomb spawn and steps in air
-- Spawn and generation
local TCATSPA = 2.0 -- 3D noise threshold for initial chamber
local TCATA = -2.0 -- 3D noise for generation limit
local GEN = true -- Enable spawn and generation
local OBCHECK = true -- Enable chamber obstruction check
local ABMINT = 1 -- ABM interval multiplier, 1 = fast generation
-- Spawn and generation noise
local np_cata = {
offset = 0,
scale = 1,
spread = {x = 256, y = 256, z = 256},
seed = 5829058,
octaves = 3,
persist = 0.5,
lacunarity = 2.0,
--flags = ""
}
-- Passages
local MINPLEN = 3 -- Min max length
local MAXPLEN = 32
local MINPWID = 3 -- Min max outer width
local MAXPWID = 24
-- Chambers
local MINCWID = 6 -- Min max outer EW NS widths, min max outer height.
local MAXCWID = 32
local MINCHEI = 6
local MAXCHEI = 32
-- Nodes
minetest.register_node("catacomb:cobble", {
description = "Mod cobblestone",
tiles = {"default_cobble.png"},
is_ground_content = false,
groups = {cracky = 3, stone = 2},
drop = "default:cobble",
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("catacomb:stairn", {
description = "Stair north",
tiles = {"default_cobble.png"},
drawtype = "nodebox",
paramtype = "light",
is_ground_content = false,
groups = {cracky = 3, stone = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{-0.5, 0, 0, 0.5, 0.5, 0.5},
},
},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("catacomb:stairs", {
description = "Stair south",
tiles = {"default_cobble.png"},
drawtype = "nodebox",
paramtype = "light",
is_ground_content = false,
groups = {cracky = 3, stone = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{-0.5, 0, -0.5, 0.5, 0.5, 0},
},
},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("catacomb:staire", {
description = "Stair East",
tiles = {"default_cobble.png"},
drawtype = "nodebox",
paramtype = "light",
is_ground_content = false,
groups = {cracky = 3, stone = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{0, 0, -0.5, 0.5, 0.5, 0.5},
},
},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("catacomb:stairw", {
description = "Stair west",
tiles = {"default_cobble.png"},
drawtype = "nodebox",
paramtype = "light",
is_ground_content = false,
groups = {cracky = 3, stone = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{-0.5, 0, -0.5, 0, 0.5, 0.5},
},
},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("catacomb:chambern", {
description = "Chamber spawner north",
tiles = {"default_cobble.png"},
is_ground_content = false,
groups = {cracky = 3, stone = 2},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("catacomb:chambers", {
description = "Chamber spawner south",
tiles = {"default_cobble.png"},
is_ground_content = false,
groups = {cracky = 3, stone = 2},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("catacomb:chambere", {
description = "Chamber spawner east",
tiles = {"default_cobble.png"},
is_ground_content = false,
groups = {cracky = 3, stone = 2},
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("catacomb:chamberw", {
description = "Chamber spawner west",
tiles = {"default_cobble.png"},
is_ground_content = false,
groups = {cracky = 3, stone = 2},
sounds = default.node_sound_stone_defaults(),
})
-- On generated function
minetest.register_on_generated(function(minp, maxp, seed)
local x0 = minp.x
local y0 = minp.y
local z0 = minp.z
local x1 = maxp.x
local y1 = maxp.y
local z1 = maxp.z
-- Check mapchunk is within limits
if not (x0 > XMIN and x1 < XMAX and
y0 > YMIN and y1 <= YMAXSPA and
z0 > ZMIN and z1 < ZMAX) or not GEN then
return
end
-- Check minimum point is within catacomb spawn volume
local nobj_cata = minetest.get_perlin(np_cata)
local nval_cata = nobj_cata:get3d({x = x0, y = y0, z = z0})
if nval_cata < TCATSPA then
--print ("[catacomb] Spawn noise " .. nval_cata)
return
end
-- Check for nearby catacomb cobble
local sidelen = x1 - x0 + 1
local sidelen2 = sidelen * 2
local c_catcobble = minetest.get_content_id("catacomb:cobble")
for vmvns = z0 - sidelen2, z0 + sidelen2, sidelen do -- Step sidelen
for vmvud = y0 - sidelen2, y0 + sidelen2, sidelen do
local vm = minetest.get_voxel_manip()
local pos1 = {x = x0 - sidelen2, y = vmvud, z = vmvns}
local pos2 = {x = x0 + sidelen2, y = vmvud, z = vmvns}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
for vi = 1, sidelen * 4 do
if data[vi] == c_catcobble then
print ("[catacomb] First chamber obstructed")
return
end
end
end
end
-- Spawn first chamber
local t1 = os.clock()
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_cobble = minetest.get_content_id("default:cobble")
local c_mobble = minetest.get_content_id("default:mossycobble")
local c_stobble = minetest.get_content_id("stairs:stair_cobble")
local c_chambers = minetest.get_content_id("catacomb:chambers")
local vm = minetest.get_voxel_manip()
local pos1 = {x = x0, y = y0, z = z0}
local pos2 = {x = x0 + MAXCWID, y = y0 + MAXCHEI, z = z0 + MAXCWID}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local exoffs = math.random(0, MAXCWID - 3)
for z = z0, z0 + MAXCWID do
for y = y0, y0 + MAXCHEI do
local vi = area:index(x0, y, z)
for x = x0, x0 + MAXCWID do
local nodid = data[vi]
if nodid ~= c_air
and nodid ~= c_ignore
and nodid ~= c_cobble
and nodid ~= c_mobble
and nodid ~= c_stobble then
if z == z0 and y == y0 and x == x0 + exoffs then
data[vi] = c_chambers
elseif (z > z0 and z < z0 + MAXCWID
and y > y0 and y < y0 + MAXCHEI
and x > x0 and x < x0 + MAXCWID) then
data[vi] = c_air
else
data[vi] = c_catcobble
end
end
vi = vi + 1
end
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_map()
local chugent = math.ceil((os.clock() - t1) * 1000)
print ("[catacomb] Spawn first chamber " .. chugent ..
" ms minp " .. x0 .. " " .. y0 .. " " .. z0)
end)
-- ABM
-- Chamber north
minetest.register_abm({
nodenames = {"catacomb:chambern"},
interval = 16 * ABMINT,
chance = 1,
catch_up = false,
action = function(pos, node)
--local t1 = os.clock()
local x = pos.x
local y = pos.y
local z = pos.z
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_cobble = minetest.get_content_id("default:cobble")
local c_mobble = minetest.get_content_id("default:mossycobble")
local c_leaves = minetest.get_content_id("default:leaves")
local c_jleaves = minetest.get_content_id("default:jungleleaves")
local c_apple = minetest.get_content_id("default:apple")
local c_stobble = minetest.get_content_id("stairs:stair_cobble")
local c_catcobble = minetest.get_content_id("catacomb:cobble")
local c_stairn = minetest.get_content_id("catacomb:stairn")
local c_stairs = minetest.get_content_id("catacomb:stairs")
local c_chambern = minetest.get_content_id("catacomb:chambern")
local c_chambere = minetest.get_content_id("catacomb:chambere")
local c_chamberw = minetest.get_content_id("catacomb:chamberw")
-- Measure existing chamber wall width
local vm = minetest.get_voxel_manip()
local pos1 = {x = x + MINPWID, y = y, z = z}
local pos2 = {x = x + MAXCWID, y = y, z = z}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local wallwid = MINPWID
local vi = area:index(x + MINPWID, y, z)
for i = MINPWID, MAXCWID do
if data[vi] ~= c_catcobble then
wallwid = i
break
end
vi = vi + 1
end
-- Calculate dimensions of passage and chamber
local passwid = math.random(MINPWID, math.min(MAXPWID, wallwid)) -- Width including walls
local passdlu = math.random(-1, 1) -- Passage direction, -1 down, 0 level, 1 up.
local passlen = math.random(MINPLEN, MAXPLEN)
local chamew = math.random(math.max(passwid, MINCWID), MAXCWID) - 1
local chamns = math.random(MINCWID, MAXCWID) - 1
local chamhei = math.random(MINCHEI, MAXCHEI) - 1
local chamhoff = -math.random(0, chamew + 1 - passwid) -- Chamber W offset relative to passage
local chamvoff = math.min(passdlu * passlen, passlen - 1)
local exoffn = math.random(0, chamew - 3)
local exoffe = math.random(0, chamns - 3)
local exoffw = math.random(0, chamns - 3)
local vmvd = math.min(chamvoff, 0) -- Voxelmanip volume edges relative to spawner
local vmvu = math.max(chamvoff + chamhei, 5)
local vmvw = chamhoff
local vmve = chamhoff + chamew
local vmvn = chamns + passlen
-- Read entire volume
local vm = minetest.get_voxel_manip()
local pos1 = {x = x + vmvw, y = y + vmvd, z = z}
local pos2 = {x = x + vmve, y = y + vmvu, z = z + vmvn}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local vvii = emax.x - emin.x + 1
local nvii = (emax.y - emin.y + 1) * vvii
local vi = area:index(x, y, z) -- Remove spawner
data[vi] = c_catcobble
-- Check for obstruction
if OBCHECK then
for k = passlen + 1, vmvn do
for j = chamvoff, chamvoff + chamhei do
local vi = area:index(x + chamhoff, y + j, z + k)
for i = 0, chamew do
local nodid = data[vi]
if nodid == c_catcobble then
vm:set_data(data) -- To remove spawner
vm:write_to_map()
vm:update_map()
--print ("[catacomb] Chamber obstructed")
return
end
vi = vi + 1
end
end
end
end
-- Carve hole in chamber wall
local vi = area:index(x + 1, y + 1, z)
for j = 1, 4 do
for i = 1, passwid - 2 do
data[vi] = c_air
vi = vi + 1
end
vi = vi - passwid + 2 + vvii -- Back 2, up 1.
end
-- Spawn passage
local vi = area:index(x, y, z + 1)
for k = 1, passlen do
for j = 1, 6 do
for i = 1, passwid do
local nodid = data[vi]
if nodid ~= c_ignore then
if passdlu ~= 0 and j == 1 -- steps spawn in underground air
and not (passdlu == 1 and k == 1)
and not (passdlu == -1 and k == len)
and (i >= 2 and i <= passwid - 1)
and (nodid ~= c_air or y <= YMAXSPA) then
if passdlu == -1 then
data[vi] = c_stairs
data[vi - vvii] = c_catcobble
else
data[vi] = c_stairn
data[vi - vvii] = c_catcobble
end
elseif passdlu == 0 and j == 1 and
(i >= 2 and i <= passwid - 1) then
data[vi] = c_catcobble -- Level passage floor spawns in air
elseif nodid ~= c_air then
if j == 1 or j == 6 or i == 1 or i == passwid then
data[vi] = c_catcobble
else
data[vi] = c_air
end
end
end
vi = vi + 1 -- Eastwards 1
end
vi = vi - passwid + vvii -- Back passwid, up 1.
end
vi = vi + (passdlu - 6) * vvii + nvii -- Down 5 or 6 or 7, northwards 1.
end
-- Decide whether to place spawners in chamber
local nobj_cata = minetest.get_perlin(np_cata)
local spawn = GEN and nobj_cata:get3d(
{x = x + chamhoff, y = y + chamvoff, z = z + vmvn}) > TCATA and
x > XMIN and x < XMAX and y > YMIN and y < YMAX and z > ZMIN and z < ZMAX
-- Spawn chamber
for k = passlen + 1, vmvn do
for j = chamvoff, chamvoff + chamhei do
local vi = area:index(x + chamhoff, y + j, z + k)
for i = 0, chamew do
local nodid = data[vi]
if nodid ~= c_air
and nodid ~= c_ignore
and nodid ~= c_cobble -- Default dungeons remain TODO update for new dungeons
and nodid ~= c_mobble
and nodid ~= c_stobble then
if spawn and k == vmvn and j == chamvoff and i == exoffn then
data[vi] = c_chambern
elseif spawn and i == chamew and j == chamvoff and
k == passlen + 1 + exoffe then
data[vi] = c_chambere
elseif spawn and i == 0 and j == chamvoff and
k == passlen + 1 + exoffw then
data[vi] = c_chamberw
elseif (k > passlen + 1 and k < vmvn and j > chamvoff and
j < chamvoff + chamhei and i > 0 and i < chamew) or
(k == passlen + 1 and j > chamvoff and j <= chamvoff + 4 and
(i > -chamhoff and i < -chamhoff + passwid - 1)) then
data[vi] = c_air
else
data[vi] = c_catcobble
end
end
vi = vi + 1
end
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_map()
--local chugent = math.ceil((os.clock() - t1) * 1000)
--print ("[catacomb] Chamber North " .. chugent .. "ms")
end,
})
-- Chamber south
minetest.register_abm({
nodenames = {"catacomb:chambers"},
interval = 17 * ABMINT,
chance = 1,
catch_up = false,
action = function(pos, node)
--local t1 = os.clock()
local x = pos.x
local y = pos.y
local z = pos.z
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_cobble = minetest.get_content_id("default:cobble")
local c_mobble = minetest.get_content_id("default:mossycobble")
local c_leaves = minetest.get_content_id("default:leaves")
local c_jleaves = minetest.get_content_id("default:jungleleaves")
local c_apple = minetest.get_content_id("default:apple")
local c_stobble = minetest.get_content_id("stairs:stair_cobble")
local c_catcobble = minetest.get_content_id("catacomb:cobble")
local c_stairn = minetest.get_content_id("catacomb:stairn")
local c_stairs = minetest.get_content_id("catacomb:stairs")
local c_chambers = minetest.get_content_id("catacomb:chambers")
local c_chambere = minetest.get_content_id("catacomb:chambere")
local c_chamberw = minetest.get_content_id("catacomb:chamberw")
local vm = minetest.get_voxel_manip()
local pos1 = {x = x + MINPWID, y = y, z = z}
local pos2 = {x = x + MAXCWID, y = y, z = z}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local wallwid = MINPWID
local vi = area:index(x + MINPWID, y, z)
for i = MINPWID, MAXCWID do
if data[vi] ~= c_catcobble then
wallwid = i
break
end
vi = vi + 1
end
local passwid = math.random(MINPWID, math.min(MAXPWID, wallwid)) -- width including walls
local passdlu = math.random(-1, 1) -- passage direction, -1 down, 0 level, 1 up
local passlen = math.random(MINPLEN, MAXPLEN)
local chamew = math.random(math.max(passwid, MINCWID), MAXCWID) - 1
local chamns = math.random(MINCWID, MAXCWID) - 1
local chamhei = math.random(MINCHEI, MAXCHEI) - 1
local chamhoff = -math.random(0, chamew + 1 - passwid) -- chamber W offset relative to passage
local chamvoff = math.min(passdlu * passlen, passlen - 1)
local exoffs = math.random(0, chamew - 3)
local exoffe = math.random(0 + 3, chamns)
local exoffw = math.random(0 + 3, chamns)
local vmvd = math.min(chamvoff, 0) -- voxel manip volume edges relative to spawner
local vmvu = math.max(chamvoff + chamhei, 5)
local vmvw = chamhoff
local vmve = chamhoff + chamew
local vmvs = chamns + passlen
local vm = minetest.get_voxel_manip()
local pos1 = {x = x + vmvw, y = y + vmvd, z = z - vmvs}
local pos2 = {x = x + vmve, y =y + vmvu, z = z}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local vvii = emax.x - emin.x + 1
local nvii = (emax.y - emin.y + 1) * vvii
local vi = area:index(x, y, z) -- remove spawner
data[vi] = c_catcobble
if OBCHECK then -- check for obstruction
for k = passlen + 1, vmvs do
for j = chamvoff, chamvoff + chamhei do
local vi = area:index(x + chamhoff, y + j, z - k)
for i = 0, chamew do
local nodid = data[vi]
if nodid == c_catcobble then
vm:set_data(data) -- abort chamber spawn
vm:write_to_map()
vm:update_map()
--print ("[catacomb] Chamber obstructed")
return
end
vi = vi + 1
end
end
end
end
local vi = area:index(x + 1, y + 1, z) -- spawn passage
for j = 1, 4 do -- carve hole in chamber wall
for i = 1, passwid - 2 do
data[vi] = c_air
vi = vi + 1
end
vi = vi - passwid + 2 + vvii -- back 2, up 1
end
local vi = area:index(x, y, z - 1)
for k = 1, passlen do
for j = 1, 6 do
for i = 1, passwid do
local nodid = data[vi]
if nodid ~= c_ignore then
if passdlu ~= 0 and j == 1
and not (passdlu == 1 and k == 1)
and not (passdlu == -1 and k == len)
and (i >= 2 and i <= passwid - 1)
and (nodid ~= c_air or y <= YMAXSPA) then
if passdlu == -1 then
data[vi] = c_stairn
data[vi - vvii] = c_catcobble
else
data[vi] = c_stairs
data[vi - vvii] = c_catcobble
end
elseif passdlu == 0 and j == 1 and
(i >= 2 and i <= passwid - 1) then
data[vi] = c_catcobble
elseif nodid ~= c_air then
if j == 1 or j == 6 or i == 1 or i == passwid then
data[vi] = c_catcobble
else
data[vi] = c_air
end
end
end
vi = vi + 1 -- eastwards 1
end
vi = vi - passwid + vvii -- back passwid, up 1
end
vi = vi + (passdlu - 6) * vvii - nvii -- down 5 or 6 or 7, southwards 1
end
-- Decide whether to place spawners in chamber
local nobj_cata = minetest.get_perlin(np_cata)
local spawn = GEN and nobj_cata:get3d(
{x = x + chamhoff, y = y + chamvoff, z = z - vmvs}) > TCATA and
x > XMIN and x < XMAX and y > YMIN and y < YMAX and z > ZMIN and z < ZMAX
for k = passlen + 1, vmvs do -- spawn chamber
for j = chamvoff, chamvoff + chamhei do
local vi = area:index(x + chamhoff, y + j, z - k)
for i = 0, chamew do
local nodid = data[vi]
if nodid ~= c_air
and nodid ~= c_ignore
and nodid ~= c_cobble -- default dungeons remain
and nodid ~= c_mobble
and nodid ~= c_stobble then
if spawn and k == vmvs and j == chamvoff and i == exoffs then
data[vi] = c_chambers
elseif spawn and i == chamew and j == chamvoff and
k == passlen + 1 + exoffe then
data[vi] = c_chambere
elseif spawn and i == 0 and j == chamvoff and
k == passlen + 1 + exoffw then
data[vi] = c_chamberw
elseif (k > passlen + 1 and k < vmvs and j > chamvoff and
j < chamvoff + chamhei and i > 0 and i < chamew) or
(k == passlen + 1 and j > chamvoff and j <= chamvoff + 4 and
(i > -chamhoff and i < -chamhoff + passwid - 1)) then
data[vi] = c_air
else
data[vi] = c_catcobble
end
end
vi = vi + 1
end
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_map()
--local chugent = math.ceil((os.clock() - t1) * 1000)
--print ("[catacomb] Chamber south " .. chugent .. "ms")
end,
})
-- Chamber east
minetest.register_abm({
nodenames = {"catacomb:chambere"},
interval = 18 * ABMINT,
chance = 1,
catch_up = false,
action = function(pos, node)
--local t1 = os.clock()
local x = pos.x
local y = pos.y
local z = pos.z
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_cobble = minetest.get_content_id("default:cobble")
local c_mobble = minetest.get_content_id("default:mossycobble")
local c_leaves = minetest.get_content_id("default:leaves")
local c_jleaves = minetest.get_content_id("default:jungleleaves")
local c_apple = minetest.get_content_id("default:apple")
local c_stobble = minetest.get_content_id("stairs:stair_cobble")
local c_catcobble = minetest.get_content_id("catacomb:cobble")
local c_staire = minetest.get_content_id("catacomb:staire")
local c_stairw = minetest.get_content_id("catacomb:stairw")
local c_chambern = minetest.get_content_id("catacomb:chambern")
local c_chambers = minetest.get_content_id("catacomb:chambers")
local c_chambere = minetest.get_content_id("catacomb:chambere")
local vm = minetest.get_voxel_manip()
local pos1 = {x = x, y = y, z = z + MINPWID}
local pos2 = {x = x, y = y, z = z + MAXCWID}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local vvii = emax.x - emin.x + 1
local nvii = (emax.y - emin.y + 1) * vvii
local wallwid = MINPWID
local vi = area:index(x, y, z + MINPWID)
for i = MINPWID, MAXCWID do
if data[vi] ~= c_catcobble then
wallwid = i
break
end
vi = vi + nvii
end
local passwid = math.random(MINPWID, math.min(MAXPWID, wallwid)) -- width including walls
local passdlu = math.random(-1, 1) -- passage direction, -1 down, 0 level, 1 up
local passlen = math.random(MINPLEN, MAXPLEN)
local chamns = math.random(math.max(passwid, MINCWID), MAXCWID) - 1
local chamew = math.random(MINCWID, MAXCWID) - 1
local chamhei = math.random(MINCHEI, MAXCHEI) - 1
local chamhoff = -math.random(0, chamns + 1 - passwid) -- chamber S offset relative to passage
local chamvoff = math.min(passdlu * passlen, passlen - 1)
local exoffe = math.random(0, chamns - 3)
local exoffn = math.random(0, chamew - 3)
local exoffs = math.random(0, chamew - 3)
local vmvd = math.min(chamvoff, 0) -- voxel manip volume edges relative to spawner
local vmvu = math.max(chamvoff + chamhei, 5)
local vmvs = chamhoff
local vmvn = chamhoff + chamns
local vmve = chamew + passlen
local vm = minetest.get_voxel_manip()
local pos1 = {x = x, y = y + vmvd, z = z + vmvs}
local pos2 = {x=x + vmve, y = y + vmvu, z = z + vmvn}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local vvii = emax.x - emin.x + 1
local nvii = (emax.y - emin.y + 1) * vvii
local vi = area:index(x, y, z) -- remove spawner
data[vi] = c_catcobble
if OBCHECK then -- check for obstruction
for k = chamhoff, vmvn do
for j = chamvoff, chamvoff + chamhei do
local vi = area:index(x + passlen + 1, y + j, z + k)
for i = 0, chamew do
local nodid = data[vi]
if nodid == c_catcobble then
vm:set_data(data) -- abort chamber spawn
vm:write_to_map()
vm:update_map()
--print ("[catacomb] Chamber obstructed")
return
end
vi = vi + 1
end
end
end
end
local vi = area:index(x, y + 1, z + 1) -- spawn passage
for j = 1, 4 do -- carve hole in chamber wall
for k = 1, passwid - 2 do
data[vi] = c_air
vi = vi + nvii
end
vi = vi - (passwid - 2) * nvii + vvii -- back 2, up 1
end
local vi = area:index(x + 1, y, z)
for i = 1, passlen do
for j = 1, 6 do
for k = 1, passwid do
local nodid = data[vi]
if nodid ~= c_ignore then
if passdlu ~= 0 and j == 1
and not (passdlu == 1 and i == 1)
and not (passdlu == -1 and i == len)
and (k >= 2 and k <= passwid - 1)
and (nodid ~= c_air or y <= YMAXSPA) then
if passdlu == -1 then
data[vi] = c_stairw
data[vi - vvii] = c_catcobble
else
data[vi] = c_staire
data[vi - vvii] = c_catcobble
end
elseif passdlu == 0 and j == 1 and
(k >= 2 and k <= passwid - 1) then
data[vi] = c_catcobble
elseif nodid ~= c_air then
if j == 1 or j == 6 or k == 1 or k == passwid then
data[vi] = c_catcobble
else
data[vi] = c_air
end
end
end
vi = vi + nvii -- northwards 1
end
vi = vi - passwid * nvii + vvii -- back passwid, up 1
end
vi = vi + (passdlu - 6) * vvii + 1 -- down 5 or 6 or 7, eastwards 1
end
-- Decide whether to place spawners in chamber
local nobj_cata = minetest.get_perlin(np_cata)
local spawn = GEN and nobj_cata:get3d(
{x = x + vmve, y = y + chamvoff, z = z + chamhoff}) > TCATA and
x > XMIN and x < XMAX and y > YMIN and y < YMAX and z > ZMIN and z < ZMAX
for k = chamhoff, vmvn do -- spawn chamber
for j = chamvoff, chamvoff + chamhei do
local vi = area:index(x + passlen + 1, y + j, z + k)
for i = 0, chamew do
local nodid = data[vi]
if nodid ~= c_air
and nodid ~= c_ignore
and nodid ~= c_cobble -- default dungeons remain
and nodid ~= c_mobble
and nodid ~= c_stobble then
if spawn and k == chamhoff + exoffe and
j == chamvoff and i == chamew then
data[vi] = c_chambere
elseif spawn and i == exoffn and j == chamvoff and k == vmvn then
data[vi] = c_chambern
elseif spawn and i == exoffs and j == chamvoff and k == chamhoff then
data[vi] = c_chambers
elseif (k > chamhoff and k < vmvn and j > chamvoff and
j < chamvoff + chamhei and i > 0 and i < chamew) or
(i == 0 and j > chamvoff and j <= chamvoff + 4 and
(k > 0 and k < passwid - 1)) then
data[vi] = c_air
else
data[vi] = c_catcobble
end
end
vi = vi + 1
end
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_map()
--local chugent = math.ceil((os.clock() - t1) * 1000)
--print ("[catacomb] Chamber east " .. chugent .. "ms")
end,
})
-- Chamber west
minetest.register_abm({
nodenames = {"catacomb:chamberw"},
interval = 19 * ABMINT,
chance = 1,
catch_up = false,
action = function(pos, node)
--local t1 = os.clock()
local x = pos.x
local y = pos.y
local z = pos.z
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
local c_cobble = minetest.get_content_id("default:cobble")
local c_mobble = minetest.get_content_id("default:mossycobble")
local c_leaves = minetest.get_content_id("default:leaves")
local c_jleaves = minetest.get_content_id("default:jungleleaves")
local c_apple = minetest.get_content_id("default:apple")
local c_stobble = minetest.get_content_id("stairs:stair_cobble")
local c_catcobble = minetest.get_content_id("catacomb:cobble")
local c_staire = minetest.get_content_id("catacomb:staire")
local c_stairw = minetest.get_content_id("catacomb:stairw")
local c_chambern = minetest.get_content_id("catacomb:chambern")
local c_chambers = minetest.get_content_id("catacomb:chambers")
local c_chamberw = minetest.get_content_id("catacomb:chamberw")
local vm = minetest.get_voxel_manip()
local pos1 = {x = x, y = y, z = z + MINPWID}
local pos2 = {x = x, y = y, z = z + MAXCWID}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local vvii = emax.x - emin.x + 1
local nvii = (emax.y - emin.y + 1) * vvii
local wallwid = MINPWID
local vi = area:index(x, y, z + MINPWID)
for i = MINPWID, MAXCWID do
if data[vi] ~= c_catcobble then
wallwid = i
break
end
vi = vi + nvii
end
local passwid = math.random(MINPWID, math.min(MAXPWID, wallwid)) -- width including walls
local passdlu = math.random(-1, 1) -- passage direction, -1 down, 0 level, 1 up
local passlen = math.random(MINPLEN, MAXPLEN)
local chamns = math.random(math.max(passwid, MINCWID), MAXCWID) - 1
local chamew = math.random(MINCWID, MAXCWID) - 1
local chamhei = math.random(MINCHEI, MAXCHEI) - 1
local chamhoff = -math.random(0, chamns + 1 - passwid) -- chamber S offset relative to passage
local chamvoff = math.min(passdlu * passlen, passlen - 1)
local exoffw = math.random(0, chamns - 3)
local exoffn = math.random(0, chamew - 3)
local exoffs = math.random(0, chamew - 3)
local vmvd = math.min(chamvoff, 0) -- voxel manip volume edges relative to spawner
local vmvu = math.max(chamvoff + chamhei, 5)
local vmvs = chamhoff
local vmvn = chamhoff + chamns
local vmvw = chamew + passlen
local vm = minetest.get_voxel_manip()
local pos1 = {x = x - vmvw, y = y + vmvd, z = z + vmvs}
local pos2 = {x = x, y = y + vmvu, z = z + vmvn}
local emin, emax = vm:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
local data = vm:get_data()
local vvii = emax.x - emin.x + 1
local nvii = (emax.y - emin.y + 1) * vvii
local vi = area:index(x, y, z) -- remove spawner
data[vi] = c_catcobble
if OBCHECK then -- check for obstruction
for k = chamhoff, vmvn do
for j = chamvoff, chamvoff + chamhei do
local vi = area:index(x - vmvw, y + j, z + k)
for i = 0, chamew - 1 do
local nodid = data[vi]
if nodid == c_catcobble then
vm:set_data(data) -- abort chamber spawn
vm:write_to_map()
vm:update_map()
--print ("[catacomb] Chamber obstructed")
return
end
vi = vi + 1
end
end
end
end
local vi = area:index(x, y + 1, z + 1) -- spawn passage
for j = 1, 4 do -- carve hole in chamber wall
for k = 1, passwid - 2 do
data[vi] = c_air
vi = vi + nvii
end
vi = vi - (passwid - 2) * nvii + vvii -- back 2, up 1
end
local vi = area:index(x - 1, y, z)
for i = 1, passlen do
for j = 1, 6 do
for k = 1, passwid do
local nodid = data[vi]
if nodid ~= c_ignore then
if passdlu ~= 0 and j == 1
and not (passdlu == 1 and i == 1)
and not (passdlu == -1 and i == len)
and (k >= 2 and k <= passwid - 1)
and (nodid ~= c_air or y <= YMAXSPA) then
if passdlu == -1 then
data[vi] = c_staire
data[vi - vvii] = c_catcobble
else
data[vi] = c_stairw
data[vi - vvii] = c_catcobble
end
elseif passdlu == 0 and j == 1 and
(k >= 2 and k <= passwid - 1) then
data[vi] = c_catcobble
elseif nodid ~= c_air then
if j == 1 or j == 6 or k == 1 or k == passwid then
data[vi] = c_catcobble
else
data[vi] = c_air
end
end
end
vi = vi + nvii -- northwards 1
end
vi = vi - passwid * nvii + vvii -- back passwid, up 1
end
vi = vi + (passdlu - 6) * vvii - 1 -- down 5 or 6 or 7, westwards 1
end
-- Decide whether to place spawners in chamber
local nobj_cata = minetest.get_perlin(np_cata)
local spawn = GEN and nobj_cata:get3d(
{x = x - vmvw, y = y + chamvoff, z = z + chamhoff}) > TCATA and
x > XMIN and x < XMAX and y > YMIN and y < YMAX and z > ZMIN and z < ZMAX
for k = chamhoff, vmvn do -- spawn chamber
for j = chamvoff, chamvoff + chamhei do
local vi = area:index(x - vmvw, y + j, z + k)
for i = 0, chamew - 1 do
local nodid = data[vi]
if nodid ~= c_air
and nodid ~= c_ignore
and nodid ~= c_cobble -- default dungeons remain
and nodid ~= c_mobble
and nodid ~= c_stobble then
if spawn and k == chamhoff + exoffw and j == chamvoff and i == 0 then
data[vi] = c_chamberw
elseif spawn and i == exoffn and j == chamvoff and k == vmvn then
data[vi] = c_chambern
elseif spawn and i == exoffs and j == chamvoff and k == chamhoff then
data[vi] = c_chambers
elseif (k > chamhoff and k < vmvn and j > chamvoff and
j < chamvoff + chamhei and i > 0 and i < chamew - 1) or
(i == chamew - 1 and j > chamvoff and j <= chamvoff + 4 and
(k > 0 and k < passwid - 1)) then
data[vi] = c_air
else
data[vi] = c_catcobble
end
end
vi = vi + 1
end
end
end
vm:set_data(data)
vm:write_to_map()
vm:update_map()
--local chugent = math.ceil((os.clock() - t1) * 1000)
--print ("[catacomb] Chamber west " .. chugent .. "ms")
end,
})