diff --git a/fortress.lua b/fortress.lua index a6d40dd..516d438 100644 --- a/fortress.lua +++ b/fortress.lua @@ -1,4 +1,6 @@ local max_depth = 31000 +local cells = 10 +local cell_size = 60 / cells dofile(fun_caves.path .. "/trophies.lua") @@ -36,6 +38,12 @@ newnode.tiles = {'fun_caves_blank.png'} newnode.pointable = false minetest.register_node("fun_caves:dungeon_wall_invisible", newnode) +newnode = fun_caves.clone_node("default:meselamp") +newnode.description = "Dungeon Light" +newnode.light_source = 10 +newnode.groups = {fortress = 1} +minetest.register_node("fun_caves:dungeon_light", newnode) + local treasures = { {'fun_caves:aquamarine', 'fun_caves:garnet', 'fun_caves:zoisite', 'fun_caves:coral_gem', 'fun_caves:moonstone', 'fun_caves:pure_copper', 'fun_caves:sky_iron', 'fun_caves:sky_iron', 'fun_caves:sky_iron', 'fun_caves:sky_iron', 'default:obsidian'}, @@ -154,9 +162,121 @@ function unionfind(max) end --- Now back to the actual fortress code... +local function maze_floor(y2, minp, maxp, data, area, node) + -- walls is zero-based. + local walls = {} + for i = 0, 2 * cells * cells - 1 do + walls[i] = i + end + table.shuffle(walls) -fun_caves.fortress = function(minp, maxp, data, area, node) + local set = unionfind(cells * cells) + + -- Remove walls in a continuous path. + for m = 0, #walls-1 do + local c = walls[m] + local a = math.floor(c / 2) + local i = a % cells + local j = math.floor(a / cells) + local u = c % 2 == 0 and 1 or 0 + local v = c % 2 == 1 and 1 or 0 + local b = a + u + cells * v + if i < cells - u and j < cells - v and set:find(a) ~= set:find(b) then + set:union(a, b) + local x = (i + u) * cell_size + minp.x + local y = minp.y + y2 * cell_size + local z = (j + v) * cell_size + minp.z + + for z1 = z + (1-v), z + (1-v) * (cell_size - 1) do + for y1 = y + 1, y + (cell_size - 1) do + local ivm = area:index(x + (1-u), y1, z1) + for x1 = x + (1-u), x + (1-u) * (cell_size - 1) do + if x1 < maxp.x and z1 < maxp.z and x1 > minp.x and z1 > minp.z then + data[ivm] = node["air"] + end + ivm = ivm + 1 + end + end + end + end + end +end + + +local designs = { + { + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0}, + }, +} +local function design_floor(y2, minp, maxp, data, area, node) + local design = designs[math.random(#designs)] + + local py = minp.y + y2 * cell_size + for z = 1, 10 do + for x = 1, 9 do + if design[z * 2 - 1][x * 2] == 0 then + local px = minp.x + x * cell_size + local pz = minp.z + (z - 1) * cell_size + for z1 = pz + 1, pz + cell_size - 1 do + local ivm = area:index(px, py + 1, z1) + for y1 = py + 1, py + cell_size - 1 do + data[ivm] = node['air'] + ivm = ivm + area.ystride + end + end + end + end + end + for z = 1, 9 do + for x = 1, 10 do + if design[z * 2][x * 2 - 1] == 0 then + local px = minp.x + (x - 1) * cell_size + local pz = minp.z + z * cell_size + for x1 = px + 1, px + cell_size - 1 do + local ivm = area:index(x1, py + 1, pz) + for y1 = py + 1, py + cell_size - 1 do + data[ivm] = node['air'] + ivm = ivm + area.ystride + end + end + end + end + end + for z = 1, 9 do + for x = 1, 9 do + if design[z * 2][x * 2] == 0 then + local px = minp.x + x * cell_size + local pz = minp.z + z * cell_size + local ivm = area:index(px, py + 1, pz) + for y1 = py + 1, py + cell_size - 1 do + data[ivm] = node['air'] + ivm = ivm + area.ystride + end + end + end + end +end + + +fun_caves.fortress = function(minp_in, maxp_in, data, area, node) -- hungry maze -- chests (w traps) -- step traps (math based) @@ -164,43 +284,35 @@ fun_caves.fortress = function(minp, maxp, data, area, node) -- hot/ice floors -- torches -- + local minp = vector.add(minp_in, 10) + local maxp = vector.subtract(maxp_in, 9) local level = math.min(6, math.ceil(maxp.y / math.floor(max_depth / -6))) - local n = 16 - local walls = {} local inner_floor = node['fun_caves:dungeon_floor_1'] local outer_wall = node['fun_caves:dungeon_wall_2'] local inner_wall = node['fun_caves:dungeon_wall_1'] local treasure_count = 0 - local csize = vector.add(vector.subtract(maxp, minp), 1) - local floor_1 = minetest.get_perlin_map(floor_noise_1, {x=csize.x, y=csize.z}):get2dMap_flat({x=minp.x, y=minp.z}) + local csize = vector.add(vector.subtract(maxp_in, minp_in), 1) + local floor_1 = minetest.get_perlin_map(floor_noise_1, {x=csize.x, y=csize.z}):get2dMap_flat({x=minp_in.x, y=minp_in.z}) - for y2 = 0, n-1 do + for y2 = 0, cells-1 do local floor_type = math.random(20) - --for y2 = 0, 0 do - -- walls is zero-based. - for i = 0, 2 * n * n - 1 do - walls[i] = i - end - table.shuffle(walls) - - local dox, doz = math.random(0, n-1), math.random(0, n-1) + local dox, doz = math.random(0, cells-1), math.random(0, cells-1) for z = minp.z, maxp.z do - for y = minp.y + y2 * 5, minp.y + y2 * 5 + 4 do + for y = minp.y + y2 * cell_size, minp.y + y2 * cell_size + (cell_size - 1) do local ivm = area:index(minp.x, y, z) for x = minp.x, maxp.x do if x == minp.x or z == minp.z or x == maxp.x or z == maxp.z then data[ivm] = outer_wall - elseif (y - minp.y) % 5 == 0 then - if math.floor((z - minp.z) / 5) == doz and math.floor((x - minp.x) / 5) == dox and (z - minp.z) % 5 ~= 0 and (x - minp.x) % 5 ~= 0 and y ~= minp.y then + elseif (y - minp.y) % cell_size == 0 then + if math.floor((z - minp.z) / cell_size) == doz and math.floor((x - minp.x) / cell_size) == dox and (z - minp.z) % cell_size ~= 0 and (x - minp.x) % cell_size ~= 0 and y ~= minp.y then data[ivm] = node["air"] else data[ivm] = inner_floor end - elseif (z - minp.z) % 5 == 0 or (x - minp.x) % 5 == 0 then - if y2 == 0 and math.random(3000) == 1 then - treasure_count = treasure_count + 1 - data[ivm] = node['fun_caves:coffer'] + elseif floor_type ~= 3 and ((z - minp.z) % cell_size == 0 or (x - minp.x) % cell_size == 0) then + if y == minp.y + y2 * cell_size + 3 and ((z - minp.z) % cell_size == 3 or (x - minp.x) % cell_size == 3) and math.random(5) == 1 then + data[ivm] = node['fun_caves:dungeon_light'] elseif floor_type == 1 and level > 3 then data[ivm] = node['fun_caves:dungeon_wall_invisible'] elseif floor_type == 1 then @@ -209,51 +321,32 @@ fun_caves.fortress = function(minp, maxp, data, area, node) data[ivm] = inner_wall end else - data[ivm] = node["air"] + if y2 == 0 and y == minp.y + y2 * cell_size + 1 and data[ivm - area.ystride] ~= node['air'] and math.random(300) == 1 then + treasure_count = treasure_count + 1 + data[ivm] = node['fun_caves:coffer'] + else + data[ivm] = node["air"] + end end ivm = ivm + 1 end end end - local set = unionfind(n * n) - - -- Remove walls in a continuous path. if floor_type ~= 3 then - for m = 0, #walls do - local c = walls[m] - local a = math.floor(c / 2) - local i = a % n - local j = math.floor(a / n) - local u = c % 2 == 0 and 1 or 0 - local v = c % 2 == 1 and 1 or 0 - local b = a + u + n * v - if i < n - u and j < n - v and set:find(a) ~= set:find(b) then - set:union(a, b) - local x = (i + u) * 5 + minp.x - local y = minp.y + y2 * 5 - local z = (j + v) * 5 + minp.z + local wall_type = math.random(2) - for z1 = z + (1-v), z + (1-v) * 4 do - for y1 = y + 1, y + 4 do - local ivm = area:index(x + (1-u), y1, z1) - for x1 = x + (1-u), x + (1-u) * 4 do - if x1 < maxp.x and z1 < maxp.z and x1 > minp.x and z1 > minp.z then - data[ivm] = node["air"] - end - ivm = ivm + 1 - end - end - end - end + if wall_type == 1 then + maze_floor(y2, minp, maxp, data, area, node) + else + design_floor(y2, minp, maxp, data, area, node) end end local index = 0 for z = minp.z + 1, maxp.z - 1 do for x = minp.x + 1, maxp.x - 1 do - index = index + 1 - local ivm = area:index(x, minp.y + y2 * 5, z) + local ivm = area:index(x, minp.y + y2 * cell_size, z) if floor_type == 2 then if data[ivm] ~= node['air'] and data[ivm + area.ystride] == node['air'] then @@ -264,13 +357,16 @@ fun_caves.fortress = function(minp, maxp, data, area, node) end end elseif floor_type == 3 then - if data[ivm] ~= node['air'] then - for i = 1, math.min(4, math.floor(4 * math.abs(floor_1[index]))) do - data[ivm + area.ystride * i] = node['default:dirt'] + if (y2 < 9 or (z - minp_in.z) > 16 or (x - minp_in.x) > 16) and data[ivm] ~= node['air'] then + local index = (z - minp_in.z) * csize.x + x - minp_in.x + for i = 1, math.min((cell_size - 1), math.floor((cell_size - 1) * math.abs(floor_1[index]))) do + if data[ivm + area.ystride * i] == node['air'] then + data[ivm + area.ystride * i] = node['default:dirt'] + end end end elseif floor_type == 4 then - for i = 1, 4 do + for i = 1, (cell_size - 1) do if data[ivm + area.ystride * i] == node['air'] then data[ivm + area.ystride * i] = node['default:water_source'] end diff --git a/mapgen.lua b/mapgen.lua index 68cf5c0..1475dac 100644 --- a/mapgen.lua +++ b/mapgen.lua @@ -52,8 +52,7 @@ fun_caves.is_fortress = function(pos, cs) local y = math.floor((pos.y + offset) / cs.y) -- Fortresses show up below ground. - -- Calls from the first dungeon level should return false. - if y > fortress_depth or (pos.y + offset) % cs.y > cs.y - 5 then + if y > fortress_depth then return false end @@ -61,9 +60,7 @@ fun_caves.is_fortress = function(pos, cs) local z = math.floor((pos.z + offset) / cs.z) local n = minetest.get_perlin(fortress_noise):get3d({x=x, y=y, z=z}) - if fun_caves.DEBUG and math.floor((n * 10000) % 4) == 1 then - return true - elseif math.floor((n * 10000) % 19) == 1 then + if math.floor((n * 10000) % (fun_caves.DEBUG and 4 or 19)) == 1 then return true end diff --git a/tesseract.lua b/tesseract.lua index 8b3692b..1dfe840 100644 --- a/tesseract.lua +++ b/tesseract.lua @@ -43,28 +43,21 @@ local function teleporter(user, area, power) elseif area == 'dungeon' then newpos = {} local base_pos = table.copy(pos) + base_pos.x = base_pos.x - (base_pos.x + 32) % 80 + 12 + base_pos.z = base_pos.z - (base_pos.z + 32) % 80 + 12 if power > 0 then base_pos.y = fun_caves.underzones[({'Caina','Phlegethos','Dis','Minauros', 'Phlegethos','Styx'})[power]].lower_bound end - -- check below the top level - base_pos.y = base_pos.y - (base_pos.y + 32) % 80 - 12 + base_pos.y = base_pos.y - (base_pos.y + 32) % 80 - 15 - for i = 1, 4000 do + for i = 1, 8000 do newpos = { x = base_pos.x + (math.random(5) - math.random(5)) * 80, y = base_pos.y - math.random(50) * 80, z = base_pos.z + (math.random(5) - math.random(5)) * 80, } - -- avoid walls - if newpos.x % 16 == 0 then - newpos.x = newpos.x + 1 - end - if newpos.z % 16 == 0 then - newpos.z = newpos.z + 1 - end - if fun_caves.is_fortress(newpos) then break end @@ -73,9 +66,6 @@ local function teleporter(user, area, power) if not fun_caves.is_fortress(newpos) then return end - - -- place on the top level - newpos.y = newpos.y + 10 elseif area == 'underworld' then local good = false local base_pos = table.copy(pos)