Implement /spawnstruct dungeon

This commit is contained in:
kay27 2021-03-07 03:49:34 +04:00
parent f3fb80200d
commit 45c0c576f7
2 changed files with 36 additions and 22 deletions

@ -1,5 +1,7 @@
-- FIXME: Chests may appear at openings -- FIXME: Chests may appear at openings
mcl_dungeons = {}
local mg_name = minetest.get_mapgen_setting("mg_name") local mg_name = minetest.get_mapgen_setting("mg_name")
-- Are dungeons disabled? -- Are dungeons disabled?
@ -10,6 +12,11 @@ end
local min_y = math.max(mcl_vars.mg_overworld_min, mcl_vars.mg_bedrock_overworld_max) + 1 local min_y = math.max(mcl_vars.mg_overworld_min, mcl_vars.mg_bedrock_overworld_max) + 1
local max_y = mcl_vars.mg_overworld_max - 1 local max_y = mcl_vars.mg_overworld_max - 1
-- Calculate the number of dungeon spawn attempts
-- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks).
-- Minetest chunks don't have this size, so scale the number accordingly.
local attempts = math.ceil(((mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE) ^ 3) / 8192) -- 63 = 80*80*80/8192
local dungeonsizes = { local dungeonsizes = {
{ x=5, y=4, z=5}, { x=5, y=4, z=5},
{ x=5, y=4, z=7}, { x=5, y=4, z=7},
@ -91,24 +98,20 @@ if mg_name == "v6" then
end end
-- Calculate the number of dungeon spawn attempts
-- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks).
-- Minetest chunks don't have this size, so scale the number accordingly.
local attempts = math.ceil(((mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE) ^ 3) / 8192) -- 63 = 80*80*80/8192
local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
if calls_remaining >= 1 then return end if calls_remaining >= 1 then return end
local p1, p2, dim, pr = param.p1, param.p2, param.dim, param.pr local p1, p2, dim, pr = param.p1, param.p2, param.dim, param.pr
local x, y, z = p1.x, p1.y, p1.z local x, y, z = p1.x, p1.y, p1.z
local check = not (param.dontcheck or false)
-- Check floor and ceiling: Must be *completely* solid -- Check floor and ceiling: Must be *completely* solid
local y_floor = y local y_floor = y
local y_ceiling = y + dim.y + 1 local y_ceiling = y + dim.y + 1
for tx = x, x + dim.x do for tz = z, z + dim.z do if check then for tx = x, x + dim.x do for tz = z, z + dim.z do
if not minetest.registered_nodes[mcl_mapgen_core.get_node({x = tx, y = y_floor , z = tz}).name].walkable if not minetest.registered_nodes[mcl_mapgen_core.get_node({x = tx, y = y_floor , z = tz}).name].walkable
or not minetest.registered_nodes[mcl_mapgen_core.get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end or not minetest.registered_nodes[mcl_mapgen_core.get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end
end end end end end
-- Check for air openings (2 stacked air at ground level) in wall positions -- Check for air openings (2 stacked air at ground level) in wall positions
local openings_counter = 0 local openings_counter = 0
@ -182,7 +185,7 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
end end
-- Check conditions. If okay, start generating -- Check conditions. If okay, start generating
if openings_counter < 1 or openings_counter > 5 then return end if check and (openings_counter < 1 or openings_counter > 5) then return end
minetest.log("action","[mcl_dungeons] Placing new dungeon at "..minetest.pos_to_string({x=x,y=y,z=z})) minetest.log("action","[mcl_dungeons] Placing new dungeon at "..minetest.pos_to_string({x=x,y=y,z=z}))
-- Okay! Spawning starts! -- Okay! Spawning starts!
@ -349,4 +352,13 @@ local function dungeons_nodes(minp, maxp, blockseed)
end end
end end
function mcl_dungeons.spawn_dungeon(p1, _, pr)
if not p1 or not pr or not p1.x or not p1.y or not p1.z then return end
local dim = dungeonsizes[pr:next(1, #dungeonsizes)]
local p2 = {x = p1.x+dim.x+1, y = p1.y+dim.y+1, z = p1.z+dim.z+1}
minetest.log("verbose","[mcl_dungeons] size=" ..minetest.pos_to_string(dim) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
local param = {p1=p1, p2=p2, dim=dim, pr=pr, dontcheck=true}
minetest.emerge_area(p1, p2, ecb_spawn_dungeon, param)
end
mcl_mapgen_core.register_generator("dungeons", nil, dungeons_nodes, 999999) mcl_mapgen_core.register_generator("dungeons", nil, dungeons_nodes, 999999)

@ -92,10 +92,10 @@ mcl_structures.call_struct = function(pos, struct_style, rotation, pr)
end end
end end
mcl_structures.generate_desert_well = function(pos) mcl_structures.generate_desert_well = function(pos, rot)
local newpos = {x=pos.x,y=pos.y-2,z=pos.z} local newpos = {x=pos.x,y=pos.y-2,z=pos.z}
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_desert_well.mts" local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_desert_well.mts"
return mcl_structures.place_schematic(newpos, path, "0", nil, true) return mcl_structures.place_schematic(newpos, path, rot or "0", nil, true)
end end
mcl_structures.generate_igloo = function(pos, rotation, pr) mcl_structures.generate_igloo = function(pos, rotation, pr)
@ -265,7 +265,7 @@ mcl_structures.generate_boulder = function(pos, rotation, pr)
local newpos = {x=pos.x,y=pos.y-1,z=pos.z} local newpos = {x=pos.x,y=pos.y-1,z=pos.z}
return minetest.place_schematic(newpos, path) -- don't serialize schematics for registered biome decorations, for MT 5.4.0, https://github.com/minetest/minetest/issues/10995 return minetest.place_schematic(newpos, path, rotation) -- don't serialize schematics for registered biome decorations, for MT 5.4.0, https://github.com/minetest/minetest/issues/10995
end end
local function hut_placement_callback(p1, p2, size, orientation, pr) local function hut_placement_callback(p1, p2, size, orientation, pr)
@ -284,14 +284,14 @@ mcl_structures.generate_witch_hut = function(pos, rotation, pr)
mcl_structures.place_schematic(pos, path, rotation, nil, true, nil, hut_placement_callback, pr) mcl_structures.place_schematic(pos, path, rotation, nil, true, nil, hut_placement_callback, pr)
end end
mcl_structures.generate_ice_spike_small = function(pos) mcl_structures.generate_ice_spike_small = function(pos, rotation)
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_ice_spike_small.mts" local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_ice_spike_small.mts"
return minetest.place_schematic(pos, path, "random", nil, false) -- don't serialize schematics for registered biome decorations, for MT 5.4.0 return minetest.place_schematic(pos, path, rotation or "random", nil, false) -- don't serialize schematics for registered biome decorations, for MT 5.4.0
end end
mcl_structures.generate_ice_spike_large = function(pos) mcl_structures.generate_ice_spike_large = function(pos, rotation)
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_ice_spike_large.mts" local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_ice_spike_large.mts"
return minetest.place_schematic(pos, path, "random", nil, false) -- don't serialize schematics for registered biome decorations, for MT 5.4.0 return minetest.place_schematic(pos, path, rotation or "random", nil, false) -- don't serialize schematics for registered biome decorations, for MT 5.4.0
end end
mcl_structures.generate_fossil = function(pos, rotation, pr) mcl_structures.generate_fossil = function(pos, rotation, pr)
@ -309,12 +309,12 @@ mcl_structures.generate_fossil = function(pos, rotation, pr)
} }
local r = pr:next(1, #fossils) local r = pr:next(1, #fossils)
local path = minetest.get_modpath("mcl_structures").."/schematics/"..fossils[r] local path = minetest.get_modpath("mcl_structures").."/schematics/"..fossils[r]
return mcl_structures.place_schematic(newpos, path, "random", nil, true) return mcl_structures.place_schematic(newpos, path, rotation or "random", nil, true)
end end
mcl_structures.generate_end_exit_portal = function(pos) mcl_structures.generate_end_exit_portal = function(pos, rot)
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_exit_portal.mts" local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_exit_portal.mts"
return mcl_structures.place_schematic(pos, path, "0", nil, true) return mcl_structures.place_schematic(pos, path, rot or "0", nil, true)
end end
local function shrine_placement_callback(p1, p2, size, rotation, pr) local function shrine_placement_callback(p1, p2, size, rotation, pr)
@ -401,7 +401,7 @@ mcl_structures.generate_end_portal_shrine = function(pos, rotation, pr)
local newpos = { x = pos.x - offset.x, y = pos.y, z = pos.z - offset.z } local newpos = { x = pos.x - offset.x, y = pos.y, z = pos.z - offset.z }
local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_portal_room_simple.mts" local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_portal_room_simple.mts"
mcl_structures.place_schematic(newpos, path, "0", nil, true, nil, shrine_placement_callback, pr) mcl_structures.place_schematic(newpos, path, rotation or "0", nil, true, nil, shrine_placement_callback, pr)
end end
local function temple_placement_callback(p1, p2, size, rotation, pr) local function temple_placement_callback(p1, p2, size, rotation, pr)
@ -488,7 +488,7 @@ mcl_structures.generate_desert_temple = function(pos, rotation, pr)
if newpos == nil then if newpos == nil then
return return
end end
mcl_structures.place_schematic(newpos, path, "random", nil, true, nil, temple_placement_callback, pr) mcl_structures.place_schematic(newpos, path, rotation or "random", nil, true, nil, temple_placement_callback, pr)
end end
local registered_structures = {} local registered_structures = {}
@ -534,7 +534,7 @@ end
-- Debug command -- Debug command
minetest.register_chatcommand("spawnstruct", { minetest.register_chatcommand("spawnstruct", {
params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine", params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | dungeon",
description = S("Generate a pre-defined structure near your position."), description = S("Generate a pre-defined structure near your position."),
privs = {debug = true}, privs = {debug = true},
func = function(name, param) func = function(name, param)
@ -551,7 +551,7 @@ minetest.register_chatcommand("spawnstruct", {
if param == "desert_temple" then if param == "desert_temple" then
mcl_structures.generate_desert_temple(pos, rot, pr) mcl_structures.generate_desert_temple(pos, rot, pr)
elseif param == "desert_well" then elseif param == "desert_well" then
mcl_structures.generate_desert_well(pos, rot, pr) mcl_structures.generate_desert_well(pos, rot)
elseif param == "igloo" then elseif param == "igloo" then
mcl_structures.generate_igloo(pos, rot, pr) mcl_structures.generate_igloo(pos, rot, pr)
elseif param == "witch_hut" then elseif param == "witch_hut" then
@ -568,6 +568,8 @@ minetest.register_chatcommand("spawnstruct", {
mcl_structures.generate_end_exit_portal(pos, rot, pr) mcl_structures.generate_end_exit_portal(pos, rot, pr)
elseif param == "end_portal_shrine" then elseif param == "end_portal_shrine" then
mcl_structures.generate_end_portal_shrine(pos, rot, pr) mcl_structures.generate_end_portal_shrine(pos, rot, pr)
elseif param == "dungeon" and mcl_dungeons and mcl_dungeons.spawn_dungeon then
mcl_dungeons.spawn_dungeon(pos, rot, pr)
elseif param == "" then elseif param == "" then
message = S("Error: No structure type given. Please use “/spawnstruct <type>”.") message = S("Error: No structure type given. Please use “/spawnstruct <type>”.")
errord = true errord = true