local max_depth = 31000 local cells = 10 local border = 10 local cell_size = math.floor((80 - border * 2) / cells) local cells_y = math.floor(80 / cell_size) local dead_space = 80 - cells_y * cell_size local dungeon_depth = -1 -- close to y / 80 local dungeon_noise = {offset = 0, scale = 1, seed = -4082, spread = {x = 7, y = 7, z = 7}, octaves = 4, persist = 1, lacunarity = 2} if fun_caves.path then dofile(fun_caves.path .. "/trophies.lua") dofile(fun_caves.path .. "/tesseract.lua") end -- dungeon floor, rooms newnode = fun_caves.clone_node("default:cobble") newnode.description = "Dungeon Stone" newnode.legacy_mineral = false newnode.groups.dungeon = 1 minetest.register_node("fun_caves:dungeon_floor_1", newnode) -- dungeon floor, halls newnode = fun_caves.clone_node("default:cobble") newnode.description = "Dungeon Stone" newnode.legacy_mineral = false newnode.groups.dungeon = 1 newnode.drop = 'default:cobble' minetest.register_node("fun_caves:dungeon_floor_2", newnode) -- dungeon walls, basic newnode = fun_caves.clone_node("default:cobble") newnode.description = "Dungeon Stone" newnode.groups.dungeon = 1 newnode.drop = 'default:cobble' minetest.register_node("fun_caves:dungeon_wall_1", newnode) -- dungeon walls, type 2 newnode = fun_caves.clone_node("default:cobble") newnode.description = "Dungeon Stone" newnode.groups.dungeon = 1 newnode.drop = 'default:cobble' minetest.register_node("fun_caves:dungeon_wall_2", newnode) local treasures = { { level = 1, rarity = 10, name = 'default:apple 10', }, { level = 1, rarity = 120, name = 'default:bronze_ingot 10', }, { level = 1, rarity = 30, name = 'default:coal_lump 10', }, { level = 1, rarity = 85, name = 'default:copper_ingot 10', }, { level = 1, rarity = 155, name = 'default:diamond 10', }, { level = 1, rarity = 155, name = 'default:gold_ingot 10', }, { level = 1, rarity = 200, name = 'default:mese_crystal', }, { level = 1, rarity = 240, name = 'default:obsidian', }, { level = 1, rarity = 85, name = 'default:obsidian_shard', }, { level = 1, rarity = 450, name = 'default:pick_diamond', }, { level = 1, rarity = 600, name = 'default:pick_mese', }, { level = 1, rarity = 50, name = 'default:steel_ingot 10', }, { level = 1, rarity = 450, name = 'default:sword_diamond', }, { level = 1, rarity = 400, name = 'default:sword_mese', }, { level = 1, rarity = 10, name = 'default:wood 10', }, { level = 1, rarity = 400, name = 'fun_caves:aquamarine', }, { level = 1, rarity = 400, name = 'fun_caves:constant_flame', }, { level = 1, rarity = 400, name = 'fun_caves:coral_gem', }, { level = 1, rarity = 400, name = 'fun_caves:garnet', }, { level = 2, rarity = 960, name = 'fun_caves:metallic_ice', }, { level = 2, rarity = 120, name = 'fun_caves:eternal_ice_crystal', }, { level = 1, rarity = 480, name = 'fun_caves:moon_glass 10', }, { level = 1, rarity = 240, name = 'fun_caves:moon_juice 10', }, { level = 1, rarity = 400, name = 'fun_caves:moonstone', }, { level = 1, rarity = 5000, name = 'fun_caves:philosophers_stone', }, { level = 1, rarity = 160, name = 'fun_caves:pure_copper', }, { level = 2, rarity = 175, name = 'fun_caves:silver_ingot 10', }, { level = 1, rarity = 960, name = 'fun_caves:sky_iron', }, { level = 1, rarity = 120, name = 'fun_caves:meteorite', }, { level = 1, rarity = 5000, name = 'fun_caves:unobtainium', }, } if minetest.registered_entities['mobs_monster:stone_monster'] then treasures[#treasures+1] = { level = 1, rarity = 400, name = 'mobs_monster:stone_monster', } end if minetest.registered_entities['mobs_monster:dungeon_master'] then treasures[#treasures+1] = { level = 1, rarity = 400, name = 'mobs_monster:dungeon_master', } end local chest_formspec = "size[8,9]" .. default.gui_bg .. default.gui_bg_img .. default.gui_slots .. "list[current_name;main;0,0.3;8,4;]" .. "list[current_player;main;0,4.85;8,1;]" .. "list[current_player;main;0,6.08;8,3;8]" .. "listring[current_name;main]" .. "listring[current_player;main]" .. default.get_hotbar_bg(0,4.85) local newnode = fun_caves.clone_node("default:chest") newnode.description = "Treasure Chest" newnode.on_construct = nil newnode.drop = 'default:chest' newnode.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) if not pos then return end local meta = minetest.get_meta(pos) if not meta then return end local depth = math.max(1, math.ceil(pos.y / -2000)) local level = math.max(1, math.floor(pos.y / -4900)) local ready = meta:get_string('formspec') if treasures and ready == '' then if minetest.get_modpath('tnt') and math.random(20) == 1 then minetest.set_node(pos, {name = 'tnt:tnt_burning'}) local timer = minetest.get_node_timer(pos) if timer then timer:start(5) end minetest.sound_play("default_dig_crumbly", {pos = pos, gain = 0.5, max_hear_distance = 10}) return end meta:set_string("formspec", chest_formspec) local inv = meta:get_inventory() inv:set_size("main", 8*4) local something for i = 1, 100 do for j = 1, 5 * depth do for _, tre in pairs(treasures) do if tre.name and tre.level and tre.rarity and tre.level <= level and math.random(tre.rarity) == 1 then inv:add_item('main', tre.name) something = true end end end if something then break end end end end minetest.register_node("fun_caves:coffer", newnode) fun_caves.dungeon = function(minp_in, maxp_in, data, p2data, area, node, heightmap) if not (minp_in and maxp_in and data and area and node and heightmap and type(data) == 'table' and type(heightmap) == 'table') then return end local n = minetest.get_perlin(dungeon_noise):get2d({x=minp_in.x, y=minp_in.z}) if not (n and type(n) == 'number') then return end if math.floor((n * 10000) % 13) ~= 1 then return end local center_off = cell_size * 4 + border if minp_in.y > -100 then local minp, maxp = minp_in, maxp_in local stair, avg, count = nil, 0, 0 local index = 0 for z = minp.z, maxp.z do for x = minp.x, maxp.x do index = index + 1 if not heightmap[index] or type(heightmap[index]) ~= 'number' then return end if x > minp.x + center_off and x < maxp.x - center_off and z > minp.z + center_off and z < maxp.z - center_off and heightmap[index] >= minp.y and heightmap[index] < maxp.y - 2 then stair = true avg = avg + heightmap[index] count = count + 1 end end end avg = math.ceil(avg / count) if stair then for z = -1, (cell_size * 2) do for x = -1, (cell_size * 2) do local ivm = area:index(x + minp.x + center_off, minp.y - 8, z + minp.z + center_off) for y = minp.y - 8, avg do if y > minp.y - 4 and (x == -1 or x == (cell_size * 2) or z == -1 or z == (cell_size * 2)) then data[ivm] = node['default:cobble'] elseif ((x == 2 or x == 9) and z > 1 and z < 10) or ((z == 2 or z == 9) and x > 1 and x < 10) then data[ivm] = node['default:cobble'] else local t if z < 2 then t = x elseif x > 9 then t = z + 11 elseif z > 9 then t = 33 - x else t = 44 - z end t = math.floor(t / 44 * 10 * 2 + 0.5) / 2 if x < 2 or x > 9 or z < 2 or z > 9 then if math.floor((y - minp.y) % 10 * 2 + 0.5) / 2 == t then data[ivm] = node['stairs:slab_cobble'] elseif math.floor((y - minp.y) % 10 * 2 + 0.5) / 2 == t - 0.5 then data[ivm] = node['default:cobble'] else data[ivm] = node['air'] end end end ivm = ivm + area.ystride end end end end return true, true end if minp_in.y > 0 then return end local minp = table.copy(minp_in) minp.x = minp.x + border minp.z = minp.z + border local maxp = table.copy(maxp_in) maxp.x = maxp.x - border maxp.z = maxp.z - border center_off = center_off - border local level = math.min(6, math.ceil(maxp.y / math.floor(max_depth / -6))) 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 leave_alone = {} leave_alone[node['default:cobble']] = true leave_alone[node['stairs:stair_cobble']] = true leave_alone[node['stairs:slab_cobble']] = true leave_alone['stairway'] = true for z = minp.z - 1, maxp.z + 1 do for y = minp.y, maxp.y + 1 do local ivm = area:index(minp.x - 1, y, z) for x = minp.x - 1, maxp.x + 1 do local centered_out = (z >= minp.z + center_off - 1 and z <= maxp.z - center_off + 1 and x >= minp.x + center_off - 1 and x <= maxp.x - center_off + 1) local centered_in = (z >= minp.z + center_off and z <= maxp.z - center_off and x >= minp.x + center_off and x <= maxp.x - center_off) if y > maxp.y - dead_space then if centered_out and (x == minp.x + center_off - 1 or x == maxp.x - center_off + 1 or z == minp.z + center_off - 1 or z == maxp.z - center_off + 1) then data[ivm] = node['fun_caves:dungeon_wall_1'] elseif not centered_out and y <= maxp.y then data[ivm] = node['default:stone'] elseif y <= maxp.y and not leave_alone[data[ivm]] then data[ivm] = node['air'] end elseif x == minp.x - 1 or x == maxp.x + 1 or z == minp.z - 1 or z == maxp.z + 1 then data[ivm] = node['fun_caves:dungeon_wall_1'] elseif (y == minp.y or y == maxp.y - dead_space) and not centered_in then data[ivm] = node['fun_caves:dungeon_floor_1'] end ivm = ivm + 1 end end end local content = {} for cx = 0, (cells - 1) do content[cx] = {} for cy = 0, (cells_y - 1) do content[cx][cy] = {} for cz = 0, (cells - 1) do if cy == (cells_y - 1) and (cz == 4 or cz == 5) and (cx == 4 or cx == 5) then content[cx][cy][cz] = 'room' elseif cy == 0 and (cz == 4 or cz == 5) and (cx == 4 or cx == 5) then content[cx][cy][cz] = 'room' else content[cx][cy][cz] = '4way' end end end end for cy = 0, (cells_y - 2) do local x, z = math.random(1,8), math.random(0,(cells - 1)) while cy == (cells_y - 1) and (z == 4 or z == 5) and (x == 4 or x == 5) do x, z = math.random(1,8), math.random(0,(cells - 1)) end content[x][cy][z] = 'stair1' content[x - 1][cy][z] = 'room' if cy < (cells_y - 1) then content[x][cy + 1][z] = 'room' content[x + 1][cy + 1][z] = 'room' end x, z = math.random(0,(cells - 1)), math.random(1,8) while cy == (cells_y - 1) and (z == 4 or z == 5) and (x == 4 or x == 5) do x, z = math.random(0,(cells - 1)), math.random(1,8) end content[x][cy][z] = 'stair0' content[x][cy][z - 1] = 'room' if cy < (cells_y - 1) then content[x][cy + 1][z] = 'room' content[x][cy + 1][z + 1] = 'room' end end for cx = 0, (cells - 1) do for cy = 0, (cells_y - 1) do for cz = 0, (cells - 1) do if content[cx][cy][cz] == '4way' and math.random(2) == 1 then content[cx][cy][cz] = 'room' end end end end for cz = 0, (cells - 1) do local oz = minp.z + cz * cell_size for cy = 0, (cells_y - 1) do local oy = minp.y + cy * cell_size for cx = 0, (cells - 1) do local ox = minp.x + cx * cell_size local centered_in = ((cx == 4 or cx == 5) and (cz == 4 or cz == 5)) if content[cx][cy][cz] == 'stair0' then for rz = 0, cell_size do for ry = 0, 9 do local ivm = area:index(ox, oy + ry, oz + rz) for rx = 0, (cell_size - 1) do if ry == rz + 1 and (rx == 2 or rx == 3) and (cy == (cells_y - 1) or rz < cell_size) then data[ivm] = node['stairs:stair_cobble'] p2data[ivm] = 0 elseif (ry >= rz + 1 and ry <= rz + 5) and (rx == 2 or rx == 3) then data[ivm] = 'stairway' elseif ry == rz and (rx == 2 or rx == 3) then data[ivm] = node['fun_caves:dungeon_floor_1'] elseif rz < cell_size and ry == 0 then data[ivm] = node['fun_caves:dungeon_floor_1'] elseif ry < cell_size and rz < cell_size then data[ivm] = node['fun_caves:dungeon_wall_1'] end ivm = ivm + 1 end end end elseif content[cx][cy][cz] == 'stair1' then for rz = 0, (cell_size - 1) do for ry = 0, 9 do local ivm = area:index(ox, oy + ry, oz + rz) for rx = 0, cell_size do if ry == rx + 1 and (rz == 2 or rz == 3) and (cy == (cells_y - 1) or rx < cell_size) then data[ivm] = node['stairs:stair_cobble'] p2data[ivm] = 1 elseif (ry >= rx + 1 and ry <= rx + 5) and (rz == 2 or rz == 3) then data[ivm] = 'stairway' elseif ry == rx and (rz == 2 or rz == 3) then data[ivm] = node['fun_caves:dungeon_floor_1'] elseif rx < cell_size and ry == 0 then data[ivm] = node['fun_caves:dungeon_floor_1'] elseif ry < cell_size and rx < cell_size then data[ivm] = node['fun_caves:dungeon_wall_1'] end ivm = ivm + 1 end end end else for rz = 0, (cell_size - 1) do for ry = 0, (cell_size - 1) do local ivm = area:index(ox, oy + ry, oz + rz) for rx = 0, (cell_size - 1) do if not leave_alone[data[ivm]] then if ry == 0 and (cy > 0 or not centered_in) then if content[cx][cy][cz] == 'room' then local r = math.random(5000) if r == 1 then data[ivm] = node['fun_caves:stone_with_gold_trap'] elseif r == 2 then data[ivm] = node['fun_caves:stone_with_coal_trap'] elseif r == 3 then data[ivm] = node['fun_caves:stone_with_iron_trap'] elseif r == 4 then data[ivm] = node['fun_caves:stone_with_diamond_trap'] else data[ivm] = node['fun_caves:dungeon_floor_1'] end else data[ivm] = node['fun_caves:dungeon_floor_2'] end elseif ry == (cell_size - 1) and (cy < (cells_y - 1) or not centered_in) then data[ivm] = node['fun_caves:dungeon_floor_2'] elseif content[cx][cy][cz] == 'room' then data[ivm] = node['air'] elseif content[cx][cy][cz] == '4way' and ry <= 2 and (rz == 2 or rz == 3 or rx == 2 or rx == 3) and (ox + rx >= minp.x + 2 and ox + rx <= maxp.x - 2 and oz + rz >= minp.z + 2 and oz + rz <= maxp.z - 2) then data[ivm] = node['air'] elseif ry > 0 and content[cx][cy][cz] == '4way' then data[ivm] = node['fun_caves:dungeon_wall_1'] end end ivm = ivm + 1 end end end end end end end for i = 0, #data do if data[i] == 'stairway' then data[i] = node['air'] end end return true, true, true end