forked from VoxeLibre/VoxeLibre
Big rewrite of structure spawning using voxel manipulators
This commit is contained in:
parent
a22dadf412
commit
b3efd6f681
|
@ -128,7 +128,7 @@ mcl_mobs.register_mob("mobs_mc:enderdragon", {
|
|||
on_die = function(self, pos, cmi_cause)
|
||||
if self._portal_pos then
|
||||
mcl_portals.spawn_gateway_portal()
|
||||
mcl_structures.place_structure(self._portal_pos,mcl_structures.registered_structures["end_exit_portal_open"],PseudoRandom(minetest.get_mapgen_setting("seed")),-1)
|
||||
mcl_structures.place_structure(self._portal_pos,mcl_structures.registered_structures["end_exit_portal_open"],PseudoRandom(minetest.get_mapgen_setting("seed")))
|
||||
if self._initial then
|
||||
mcl_experience.throw_xp(pos, 11500) -- 500 + 11500 = 12000
|
||||
minetest.set_node(vector.add(self._portal_pos, vector.new(0, 5, 0)), {name = "mcl_end:dragon_egg"})
|
||||
|
|
|
@ -4,34 +4,35 @@ local storage = mcl_portals.storage
|
|||
local vector = vector
|
||||
|
||||
local gateway_positions = {
|
||||
{x = 96, y = -26925, z = 0},
|
||||
{x = 91, y = -26925, z = 29},
|
||||
{x = 77, y = -26925, z = 56},
|
||||
{x = 56, y = -26925, z = 77},
|
||||
{x = 29, y = -26925, z = 91},
|
||||
{x = 0, y = -26925, z = 96},
|
||||
{x = -29, y = -26925, z = 91},
|
||||
{x = -56, y = -26925, z = 77},
|
||||
{x = -77, y = -26925, z = 56},
|
||||
{x = -91, y = -26925, z = 29},
|
||||
{x = -96, y = -26925, z = 0},
|
||||
{x = -91, y = -26925, z = -29},
|
||||
{x = -77, y = -26925, z = -56},
|
||||
{x = -56, y = -26925, z = -77},
|
||||
{x = -29, y = -26925, z = -91},
|
||||
{x = 0, y = -26925, z = -96},
|
||||
{x = 29, y = -26925, z = -91},
|
||||
{x = 56, y = -26925, z = -77},
|
||||
{x = 77, y = -26925, z = -56},
|
||||
{x = 91, y = -26925, z = -29},
|
||||
vector.new(96, -26925, 0),
|
||||
vector.new(91, -26925, 29),
|
||||
vector.new(77, -26925, 56),
|
||||
vector.new(56, -26925, 77),
|
||||
vector.new(29, -26925, 91),
|
||||
vector.new(0, -26925, 96),
|
||||
vector.new(-29, -26925, 91),
|
||||
vector.new(-56, -26925, 77),
|
||||
vector.new(-77, -26925, 56),
|
||||
vector.new(-91, -26925, 29),
|
||||
vector.new(-96, -26925, 0),
|
||||
vector.new(-91, -26925, -29),
|
||||
vector.new(-77, -26925, -56),
|
||||
vector.new(-56, -26925, -77),
|
||||
vector.new(-29, -26925, -91),
|
||||
vector.new(0, -26925, -96),
|
||||
vector.new(29, -26925, -91),
|
||||
vector.new(56, -26925, -77),
|
||||
vector.new(77, -26925, -56),
|
||||
vector.new(91, -26925, -29),
|
||||
}
|
||||
|
||||
local path_gateway_portal = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_gateway_portal.mts"
|
||||
|
||||
local function spawn_gateway_portal(pos, dest_str)
|
||||
return mcl_structures.place_schematic(vector.add(pos, vector.new(-1, -2, -1)), path_gateway_portal, "0", nil, true, nil, dest_str and function()
|
||||
minetest.get_meta(pos):set_string("mcl_portals:gateway_destination", dest_str)
|
||||
end)
|
||||
return mcl_structures.place_schematic(vector.add(pos, vector.new(-1, -2, -1)), 0, nil, nil, path_gateway_portal, "0", nil, true, nil, nil, nil,
|
||||
dest_str and function()
|
||||
minetest.get_meta(pos):set_string("mcl_portals:gateway_destination", dest_str)
|
||||
end)
|
||||
end
|
||||
|
||||
function mcl_portals.spawn_gateway_portal()
|
||||
|
|
|
@ -20,7 +20,7 @@ local function connectable(itemstring)
|
|||
return (minetest.get_item_group(itemstring, "wall") == 1) or (minetest.get_item_group(itemstring, "solid") == 1)
|
||||
end
|
||||
|
||||
local function update_wall(pos)
|
||||
function mcl_walls.update_wall(pos)
|
||||
local thisnode = minetest.get_node(pos)
|
||||
|
||||
if minetest.get_item_group(thisnode.name, "wall") == 0 then
|
||||
|
@ -67,11 +67,12 @@ local function update_wall(pos)
|
|||
|
||||
minetest.add_node(pos, {name = basename..sum})
|
||||
end
|
||||
local update_wall = mcl_walls.update_wall
|
||||
|
||||
local function update_wall_global(pos)
|
||||
for i = 1,5 do
|
||||
local dir = directions[i]
|
||||
update_wall({x = pos.x + dir.x, y = pos.y + dir.y, z = pos.z + dir.z})
|
||||
update_wall(vector.offset(pos, dir.x, dir.y, dir.z))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -269,7 +270,7 @@ function mcl_walls.register_wall(nodename, description, source, tiles, inventory
|
|||
fixed = {-4/16, -0.5, -4/16, 4/16, 1, 4/16}
|
||||
},
|
||||
collisionbox = {-0.2, 0, -0.2, 0.2, 1.4, 0.2},
|
||||
on_construct = update_wall,
|
||||
on_construct = mcl_walls.update_wall,
|
||||
sounds = sounds,
|
||||
_mcl_blast_resistance = blast_resistance,
|
||||
_mcl_hardness = hardness,
|
||||
|
|
|
@ -20,33 +20,6 @@ local function run_generators(minp, maxp, blockseed)
|
|||
end
|
||||
end
|
||||
|
||||
local function update_data (vm, data, data2)
|
||||
-- Write stuff
|
||||
vm:set_data(data)
|
||||
if param2 > 0 then
|
||||
vm:set_param2_data(data2)
|
||||
end
|
||||
end
|
||||
|
||||
local function post_generator_processing(vm, minp, maxp, deco_used, deco_table, ore_used, ore_table)
|
||||
if deco_table then
|
||||
minetest.generate_decorations(vm,vector.new(minp.x,deco_table.min,minp.z),vector.new(maxp.x,deco_table.max,maxp.z))
|
||||
elseif deco_used then
|
||||
minetest.generate_decorations(vm)
|
||||
end
|
||||
if ore_table then
|
||||
minetest.generate_ores(vm,vector.new(minp.x,ore_table.min,minp.z),vector.new(maxp.x,ore_table.max,maxp.z))
|
||||
elseif ore_used then
|
||||
minetest.generate_ores(vm)
|
||||
end
|
||||
end
|
||||
|
||||
local function post_generator_processing_2(vm, p1, p2, shadow)
|
||||
vm:calc_lighting(p1, p2, shadow)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed)
|
||||
local t1 = os.clock()
|
||||
if lvm > 0 then
|
||||
|
|
|
@ -517,4 +517,7 @@ local function fix_foliage_missed(minp, maxp, blockseed)
|
|||
end
|
||||
end
|
||||
end
|
||||
mcl_mapgen_core.register_generator("fix_foliage_missed", nil, fix_foliage_missed)
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed) -- Set correct palette indexes of missed foliage.
|
||||
fix_foliage_missed (minp, maxp)
|
||||
end)
|
||||
|
|
|
@ -7,13 +7,12 @@ local BLAZE_SPAWNER_MAX_LIGHT = 11
|
|||
|
||||
mcl_structures.register_structure("nether_outpost",{
|
||||
place_on = {"mcl_nether:netherrack","mcl_crimson:crimson_nylium","mcl_crimson:warped_nylium","mcl_blackstone:basalt","mcl_blackstone:soul_soil","mcl_blackstone:blackstone","mcl_nether:soul_sand"},
|
||||
fill_ratio = 0.01,
|
||||
chunk_probability = 900,
|
||||
chunk_probability = 23,
|
||||
flags = "all_floors",
|
||||
biomes = {"Nether","SoulsandValley","WarpedForest","CrimsonForest","BasaltDelta"},
|
||||
sidelen = 24,
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
prepare = { tolerance=20, padding=2, corners=5, foundation=true, clearance=true },
|
||||
y_min = mcl_vars.mg_lava_nether_max - 1,
|
||||
y_max = mcl_vars.mg_nether_max - 30,
|
||||
filenames = { modpath.."/schematics/mcl_nether_fortresses_nether_outpost.mts" },
|
||||
|
@ -31,17 +30,17 @@ local nbridges = {
|
|||
modpath.."/schematics/mcl_nether_fortresses_nether_bridge_4.mts",
|
||||
}
|
||||
mcl_structures.register_structure("nether_bridge",{
|
||||
place_on = {"mcl_nether:nether_lava_source","mcl_nether:netherrack","mcl_crimson:crimson_nylium","mcl_crimson:warped_nylium","mcl_blackstone:basalt","mcl_blackstone:soul_soil","mcl_blackstone:blackstone","mcl_nether:soul_sand","mcl_core:bedrock"},
|
||||
fill_ratio = 0.01,
|
||||
chunk_probability = 500,
|
||||
flags = "all_floors",
|
||||
place_on = {"mcl_nether:nether_lava_source","mcl_nether:netherrack","mcl_crimson:crimson_nylium","mcl_crimson:warped_nylium","mcl_blackstone:basalt","mcl_blackstone:soul_soil","mcl_blackstone:blackstone","mcl_nether:soul_sand"},
|
||||
chunk_probability = 5, -- because of the small height allowed, these are quite rare otherwise
|
||||
flags = "all_floors, liquid_surface",
|
||||
prepare = { tolerance=-1, clearance = 6 },
|
||||
force_placement = true,
|
||||
sidelen = 38,
|
||||
solid_ground = false,
|
||||
make_foundation = false,
|
||||
y_min = mcl_vars.mg_nether_min - 4,
|
||||
y_max = mcl_vars.mg_lava_nether_max - 20,
|
||||
y_min = mcl_vars.mg_lava_nether_max - 5,
|
||||
y_max = mcl_vars.mg_lava_nether_max + 15,
|
||||
filenames = nbridges,
|
||||
y_offset = function(pr) return pr:next(15,20) end,
|
||||
y_offset = function(pr) return pr:next(-12, -5) end,
|
||||
after_place = function(pos,def,pr)
|
||||
local p1 = vector.offset(pos,-14,0,-14)
|
||||
local p2 = vector.offset(pos,14,24,14)
|
||||
|
@ -51,35 +50,41 @@ mcl_structures.register_structure("nether_bridge",{
|
|||
|
||||
mcl_structures.register_structure("nether_outpost_with_bridges",{
|
||||
place_on = {"mcl_nether:netherrack","mcl_crimson:crimson_nylium","mcl_crimson:warped_nylium","mcl_blackstone:basalt","mcl_blackstone:soul_soil","mcl_blackstone:blackstone","mcl_nether:soul_sand","mcl_nether:nether_lava_source"},
|
||||
fill_ratio = 0.01,
|
||||
chunk_probability = 1300,
|
||||
chunk_probability = 33,
|
||||
flags = "all_floors",
|
||||
biomes = {"Nether","SoulsandValley","WarpedForest","CrimsonForest","BasaltDelta"},
|
||||
sidelen = 24,
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
prepare = { tolerance=30, padding=4, corners=5, foundation=true, clearance=true },
|
||||
y_min = mcl_vars.mg_lava_nether_max - 1,
|
||||
y_max = mcl_vars.mg_nether_max - 30,
|
||||
filenames = { modpath.."/schematics/mcl_nether_fortresses_nether_outpost.mts" },
|
||||
daughters = {{
|
||||
files = { nbridges[1] },
|
||||
pos = vector.new(0,-2,-24),
|
||||
pos = vector.new(0,-3,-25),
|
||||
rot = 180,
|
||||
prepare = { tolerance = -1, foundation = false, clearance = 14, padding = -2, corners=2 },
|
||||
},
|
||||
{
|
||||
files = { nbridges[1] },
|
||||
pos = vector.new(0,-2,24),
|
||||
pos = vector.new(0,-3,24),
|
||||
rot = 0,
|
||||
no_level = true,
|
||||
prepare = { tolerance = -1, foundation = false, clearance = 14, padding = -2, corners=2 },
|
||||
},
|
||||
{
|
||||
files = { nbridges[1] },
|
||||
pos = vector.new(-24,-2,0),
|
||||
pos = vector.new(-25,-3,0),
|
||||
rot = 270,
|
||||
no_level = true,
|
||||
prepare = { tolerance = -1, foundation = false, clearance = 14, padding = -2, corners=2 },
|
||||
},
|
||||
{
|
||||
files = { nbridges[1] },
|
||||
pos = vector.new(24,-2,0),
|
||||
pos = vector.new(24,-3,0),
|
||||
rot = 90,
|
||||
no_level = true,
|
||||
prepare = { tolerance = -1, foundation = false, clearance = 14, padding = -2, corners=2 },
|
||||
},
|
||||
},
|
||||
after_place = function(pos,def,pr)
|
||||
|
@ -97,11 +102,10 @@ mcl_structures.register_structure("nether_outpost_with_bridges",{
|
|||
end
|
||||
minetest.bulk_set_node(bricks, {name = "mcl_nether:nether_brick", param2 = 2})
|
||||
|
||||
local p1 = vector.offset(pos,-45,13,-45)
|
||||
local p2 = vector.offset(pos,45,13,45)
|
||||
local p1, p2 = vector.offset(pos,-45,12,-45), vector.offset(pos,45,22,45)
|
||||
mcl_structures.spawn_mobs("mobs_mc:witherskeleton",{"mcl_blackstone:blackstone_chiseled_polished"},p1,p2,pr,5)
|
||||
end
|
||||
},true)
|
||||
})
|
||||
|
||||
mcl_structures.register_structure_spawn({
|
||||
name = "mobs_mc:witherskeleton",
|
||||
|
@ -115,13 +119,12 @@ mcl_structures.register_structure_spawn({
|
|||
|
||||
mcl_structures.register_structure("nether_bulwark",{
|
||||
place_on = {"mcl_nether:netherrack","mcl_crimson:crimson_nylium","mcl_crimson:warped_nylium","mcl_blackstone:basalt","mcl_blackstone:soul_soil","mcl_blackstone:blackstone","mcl_nether:soul_sand"},
|
||||
fill_ratio = 0.01,
|
||||
chunk_probability = 900,
|
||||
chunk_probability = 29,
|
||||
flags = "all_floors",
|
||||
biomes = {"Nether","SoulsandValley","WarpedForest","CrimsonForest"},
|
||||
sidelen = 36,
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
prepare = { tolerance=15, padding=4, corners=4, foundation=true, clearance=true },
|
||||
y_min = mcl_vars.mg_lava_nether_max - 1,
|
||||
y_max = mcl_vars.mg_nether_max - 30,
|
||||
filenames = {
|
||||
|
@ -137,14 +140,15 @@ mcl_structures.register_structure("nether_bulwark",{
|
|||
modpath.."/schematics/mcl_nether_fortresses_nether_bulwark_interior_3.mts",
|
||||
modpath.."/schematics/mcl_nether_fortresses_nether_bulwark_interior_4.mts",
|
||||
},
|
||||
pos = vector.new(0,0,0),
|
||||
pos = vector.new(0,1,0),
|
||||
force_place = true,
|
||||
prepare = { tolerance = -1, foundation = false, clearance = false },
|
||||
},
|
||||
},
|
||||
y_offset = 0,
|
||||
construct_nodes = {"group:wall"},
|
||||
after_place = function(pos,def,pr)
|
||||
local p1 = vector.offset(pos,-14,0,-14)
|
||||
local p2 = vector.offset(pos,14,24,14)
|
||||
local p1, p2 = vector.offset(pos,-14,0,-14), vector.offset(pos,14,24,14)
|
||||
mcl_structures.spawn_mobs("mobs_mc:piglin",{"mcl_blackstone:blackstone_brick_polished","mcl_stairs:slab_blackstone_polished"},p1,p2,pr,5)
|
||||
mcl_structures.spawn_mobs("mobs_mc:piglin_brute",{"mcl_blackstone:blackstone_brick_polished","mcl_stairs:slab_blackstone_polished"},p1,p2,pr)
|
||||
mcl_structures.spawn_mobs("mobs_mc:hoglin",{"mcl_blackstone:nether_gold"},p1,p2,pr,4)
|
||||
|
|
|
@ -1,91 +1,203 @@
|
|||
mcl_structures.registered_structures = {}
|
||||
|
||||
local RANDOM_SEED_OFFSET = 959 -- random constant that should be unique across each library
|
||||
|
||||
local disabled_structures = minetest.settings:get("mcl_disabled_structures")
|
||||
if disabled_structures then disabled_structures = disabled_structures:split(",")
|
||||
else disabled_structures = {} end
|
||||
|
||||
local peaceful = minetest.settings:get_bool("only_peaceful_mobs", false)
|
||||
local mob_cap_player = tonumber(minetest.settings:get("mcl_mob_cap_player")) or 75
|
||||
local mob_cap_animal = tonumber(minetest.settings:get("mcl_mob_cap_animal")) or 10
|
||||
local structure_boost = tonumber(minetest.settings:get("mcl_structures_boost")) or 1
|
||||
local worldseed = minetest.get_mapgen_setting("seed")
|
||||
local RANDOM_SEED_OFFSET = 959 -- random constant that should be unique across each library
|
||||
|
||||
local logging = minetest.settings:get_bool("mcl_logging_structures",true)
|
||||
local logging = minetest.settings:get_bool("mcl_logging_structures", true)
|
||||
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
|
||||
local rotations = {
|
||||
"0",
|
||||
"90",
|
||||
"180",
|
||||
"270"
|
||||
}
|
||||
|
||||
local disabled_structures = minetest.settings:get("mcl_disabled_structures")
|
||||
if disabled_structures then disabled_structures = disabled_structures:split(",")
|
||||
else disabled_structures = {} end
|
||||
function mcl_structures.is_disabled(structname)
|
||||
return table.indexof(disabled_structures,structname) ~= -1
|
||||
end
|
||||
|
||||
local function ecb_place(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
minetest.place_schematic(param.pos, param.schematic, param.rotation, param.replacements, param.force_placement, param.flags)
|
||||
if param.after_placement_callback and param.p1 and param.p2 then
|
||||
param.after_placement_callback(param.p1, param.p2, param.size, param.rotation, param.pr, param.callback_param)
|
||||
end
|
||||
local ROTATIONS = { "0", "90", "180", "270" }
|
||||
function mcl_structures.parse_rotation(rotation, pr)
|
||||
if rotation == "random" and pr then return ROTATIONS[pr:next(1,#ROTATIONS)] end
|
||||
return rotation
|
||||
end
|
||||
|
||||
function mcl_structures.place_schematic(pos, schematic, rotation, replacements, force_placement, flags, after_placement_callback, pr, callback_param)
|
||||
if type(schematic) ~= "table" and not mcl_util.file_exists(schematic) then
|
||||
minetest.log("warning","[mcl_structures] schematic file "..tostring(schematic).." does not exist.")
|
||||
return end
|
||||
local s = loadstring(minetest.serialize_schematic(schematic, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic")()
|
||||
if s and s.size then
|
||||
local x, z = s.size.x, s.size.z
|
||||
if rotation then
|
||||
if rotation == "random" and pr then
|
||||
rotation = rotations[pr:next(1,#rotations)]
|
||||
end
|
||||
if rotation == "random" then
|
||||
x = math.max(x, z)
|
||||
z = x
|
||||
elseif rotation == "90" or rotation == "270" then
|
||||
x, z = z, x
|
||||
end
|
||||
--- Get the size after rotation.
|
||||
-- @param size vector: Size information
|
||||
-- @param rotation string or number: only 0, 90, 180, 270 are allowed
|
||||
-- @return vector: new vector, for safety
|
||||
function mcl_structures.size_rotated(size, rotation)
|
||||
if rotation == "90" or rotation == "270" or rotation == 90 or rotation == 270 then
|
||||
return vector.new(size.z, size.y, size.x)
|
||||
end
|
||||
return vector.copy(size)
|
||||
end
|
||||
|
||||
--- Get top left position after apply centering flags and padding.
|
||||
-- @param pos vector: Placement position
|
||||
-- @param[opt] size vector: Size information
|
||||
-- @param[opt] flags string or table: as in minetest.place_schematic, place_center_x, place_center_y
|
||||
-- @param[opt] padding number: optional margin (integer)
|
||||
-- @return vector: new vector, for safety
|
||||
function mcl_structures.top_left_from_flags(pos, size, flags, padding)
|
||||
local dx, dy, dz = 0, 0, 0
|
||||
-- must match src/mapgen/mg_schematic.cpp to be consistent
|
||||
if type(flags) == "table" then
|
||||
if flags["place_center_x"] ~= nil then dx = -math.floor((size.x-1)*0.5) end
|
||||
if flags["place_center_y"] ~= nil then dy = -math.floor((size.y-1)*0.5) end
|
||||
if flags["place_center_z"] ~= nil then dz = -math.floor((size.z-1)*0.5) end
|
||||
elseif type(flags) == "string" then
|
||||
if string.find(flags, "place_center_x") then dx = -math.floor((size.x-1)*0.5) end
|
||||
if string.find(flags, "place_center_y") then dy = -math.floor((size.y-1)*0.5) end
|
||||
if string.find(flags, "place_center_z") then dz = -math.floor((size.z-1)*0.5) end
|
||||
end
|
||||
if padding then
|
||||
dx = dx - padding
|
||||
dz = dz - padding
|
||||
end
|
||||
return vector.offset(pos, dx, dy, dz)
|
||||
end
|
||||
|
||||
-- Expected contents of param:
|
||||
-- pos vector: position (center.x, base.y, center.z) -- flags NOT supported
|
||||
-- size vector: structure size after rotation (!)
|
||||
-- yoffset number: relative to base.y, typically <= 0
|
||||
-- y_min number: minimum y range permitted
|
||||
-- y_max number: maximum y range permitted
|
||||
-- schematic string or schematic: as in minetest.place_schematic
|
||||
-- rotation string: as in minetest.place_schematic
|
||||
-- replacement table: as in minetest.place_schematic
|
||||
-- force_placement boolean: as in minetest.place_schematic
|
||||
-- prepare table: instructions for preparation (usually from definition)
|
||||
-- tolerance number: tolerable ground unevenness, -1 to disable, default 10
|
||||
-- foundation boolean or number: level ground underneath structure (true is a minimum depth of -3)
|
||||
-- clearance boolean or string or number: clear overhead area (offset, or "top" to begin over the structure only)
|
||||
-- padding number: additional padding to increase the area, default 1
|
||||
-- corners number: corner smoothing of foundation and clearance, default 1
|
||||
-- pr PcgRandom: random generator
|
||||
-- name string: for logging
|
||||
local function emerge_schematic_vm(vm, param)
|
||||
local pos, size, prepare, surface_mat = param.pos, param.size, param.prepare, nil
|
||||
-- adjust ground to a move level position
|
||||
if pos and size and prepare and (prepare.tolerance or 10) >= 0 then
|
||||
pos, surface_mat = mcl_structures.find_level(vm, pos, size, prepare.tolerance)
|
||||
if not pos then
|
||||
minetest.log("warning", "[mcl_structures] Not spawning "..tostring(param.name or param.schematic.name).." at "..minetest.pos_to_string(param.pos).." because ground is too uneven.")
|
||||
return nil
|
||||
end
|
||||
local p1 = {x=pos.x , y=pos.y , z=pos.z }
|
||||
local p2 = {x=pos.x+x-1, y=pos.y+s.size.y-1, z=pos.z+z-1}
|
||||
minetest.log("verbose", "[mcl_structures] size=" ..minetest.pos_to_string(s.size) .. ", rotation=" .. tostring(rotation) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2))
|
||||
local param = {pos=vector.new(pos), schematic=s, rotation=rotation, replacements=replacements, force_placement=force_placement, flags=flags, p1=p1, p2=p2, after_placement_callback = after_placement_callback, size=vector.new(s.size), pr=pr, callback_param=callback_param}
|
||||
minetest.emerge_area(p1, p2, ecb_place, param)
|
||||
return true
|
||||
if param.y_max and pos.y > param.y_max then pos.y = param.y_max end
|
||||
if param.y_min and pos.y < param.y_min then pos.y = param.y_min end
|
||||
end
|
||||
-- Prepare the environment
|
||||
if prepare and (prepare.clearance or prepare.foundation) then
|
||||
-- Get materials from biome:
|
||||
local b = mg_name ~= "v6" and minetest.registered_biomes[minetest.get_biome_name(minetest.get_biome_data(pos).biome)]
|
||||
local node_top = b and b.node_top or (surface_mat and surface_mat.name) or "mcl_core:dirt_with_grass"
|
||||
local node_filler = b and b.node_filler or "mcl_core:dirt"
|
||||
local node_stone = b and b.node_stone or "mcl_core:stone"
|
||||
-- FIXME: not yet used: local node_dust = b and b.node_dust
|
||||
local node_top_param2 = node_top == "mcl_core:dirt_with_grass" and b._mcl_grass_palette_index or 0 -- grass color, also other materials?
|
||||
|
||||
local corners, padding, depth = prepare.corners or 1, prepare.padding or 1, (type(prepare.foundation) == "number" and prepare.foundation) or -4
|
||||
local gp = vector.offset(pos, -math.floor((size.x-1)*0.5) - padding, 0, -math.floor((size.z-1)*0.5)-padding)
|
||||
local gs = vector.offset(size, padding*2, depth, padding*2)
|
||||
if prepare.clearance then
|
||||
-- minetest.log("action", "[mcl_structures] clearing air "..minetest.pos_to_string(gp).." +"..minetest.pos_to_string(gs).." corners "..corners)
|
||||
-- TODO: add more parameters?
|
||||
local yoff, height = 0, size.y + (param.yoffset or 0)
|
||||
if prepare.clearance == "top" or prepare.clearance == "above" then
|
||||
yoff, height = height, 0
|
||||
elseif type(prepare.clearance) == "number" then
|
||||
yoff, height = prepare.clearance, height - prepare.clearance
|
||||
end
|
||||
mcl_structures.clearance(vm, gp.x, gp.y + yoff, gp.z, gs.x, height, gs.z, corners, {name=node_top, param2=node_top_param2}, param.pr)
|
||||
end
|
||||
if prepare.foundation then
|
||||
-- minetest.log("action", "[mcl_structures] fill foundation "..minetest.pos_to_string(gp).." +"..minetest.pos_to_string(gs).." corners "..corners)
|
||||
local depth = (type(prepare.foundation) == "number" and prepare.foundation) or -3
|
||||
mcl_structures.foundation(vm, gp.x, gp.y - 1, gp.z, gs.x, depth, gs.z, corners,
|
||||
{name=node_top, param2=node_top_param2}, {name=node_filler}, {name=node_stone}, param.pr)
|
||||
end
|
||||
end
|
||||
-- place the actual schematic
|
||||
pos.y = pos.y + (param.yoffset or 0)
|
||||
minetest.place_schematic_on_vmanip(vm, pos, param.schematic, param.rotation, param.replacements, param.force_placement, "place_center_x,place_center_z")
|
||||
return pos
|
||||
end
|
||||
|
||||
-- Additional parameters:
|
||||
-- emin vector: emerge area minimum
|
||||
-- emax vector: emerge area maximum
|
||||
-- after_placement_callback function: callback after placement, (pmin, pmax, size, rotation, pr, param)
|
||||
-- callback_param table: additional parameters to callback function
|
||||
local function emerge_schematic(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining >= 1 then return end
|
||||
local vm = VoxelManip()
|
||||
vm:read_from_map(param.emin, param.emax)
|
||||
local pos = emerge_schematic_vm(vm, param)
|
||||
vm:write_to_map(true)
|
||||
if not pos then return end
|
||||
-- repair walls (TODO: port to vmanip? but no "vm.find_nodes_in_area" yet)
|
||||
local pmin = vector.offset(pos, -math.floor((param.size.x-1)*0.5), 0, -math.floor((param.size.z-1)*0.5))
|
||||
local pmax = vector.offset(pmin, param.size.x-1, param.size.y-1, param.size.z-1)
|
||||
if pmin and pmax and mcl_walls then
|
||||
for _, n in pairs(minetest.find_nodes_in_area(pmin, pmax, { "group:wall" })) do
|
||||
mcl_walls.update_wall(n)
|
||||
end
|
||||
end
|
||||
if pmin and pmax and param.after_placement_callback then
|
||||
param.after_placement_callback(pmin, pmax, param.size, param.rotation, param.pr, param.callback_param)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_structures.get_struct(file)
|
||||
local localfile = modpath.."/schematics/"..file
|
||||
local file, errorload = io.open(localfile, "rb")
|
||||
if errorload then
|
||||
minetest.log("error", "[mcl_structures] Could not open this struct: "..localfile)
|
||||
return nil
|
||||
local DEFAULT_PREPARE = { tolerance = 8, foundation = -3, clearance = false, padding = 1, corners = 1 }
|
||||
local DEFAULT_FLAGS = "place_center_x,place_center_z"
|
||||
function mcl_structures.place_schematic(pos, yoffset, y_min, y_max, schematic, rotation, replacements, force_placement, flags, prepare, pr, after_placement_callback, callback_param)
|
||||
if schematic and not schematic.size then -- e.g., igloo still passes filenames
|
||||
schematic = loadstring(minetest.serialize_schematic(schematic, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic")()
|
||||
end
|
||||
|
||||
local allnode = file:read("*a")
|
||||
file:close()
|
||||
|
||||
return allnode
|
||||
rotation = mcl_structures.parse_rotation(rotation, pr)
|
||||
local size = mcl_structures.size_rotated(schematic.size, rotation)
|
||||
-- area to emerge; note that alignment flags could be non-center, although we almost always use place_center_x,place_center_z
|
||||
local pmin = mcl_structures.top_left_from_flags(pos, flags or DEFAULT_FLAGS)
|
||||
local ppos = vector.offset(pmin, math.floor((size.x-1)*0.5), 0, math.floor((size.z-1)*0.5)) -- center
|
||||
local pmax = vector.offset(pmin, size.x - 1, size.y - 1, size.z - 1)
|
||||
if prepare == nil or prepare == true then prepare = DEFAULT_PREPARE end
|
||||
if prepare == false then prepare = {} end
|
||||
-- area to emerge. Add some margin to allow for finding better suitable ground etc.
|
||||
local emin, emax = vector.offset(pmin, -1, -5, -1), vector.offset(pmax, 1, 5, 1)
|
||||
if prepare then emin.y = emin.y - (prepare.tolerance or 10) end
|
||||
-- if we need to generate a foundation, we need to emerge a larger area:
|
||||
if prepare.foundation or prepare.clearance then
|
||||
-- these functions need some extra margins
|
||||
local padding, depth, height = (prepare.padding or 0) + 3, (prepare.depth or -4) - 15, size.y * 2 + 6
|
||||
emin = vector.offset(pmin, -padding, depth + math.min(yoffset or 0, 0), -padding)
|
||||
emax = vector.offset(pmax, padding, height + math.max(yoffset or 0, 0), padding)
|
||||
end
|
||||
minetest.emerge_area(emin, emax, emerge_schematic, {
|
||||
emin=emin, emax=emax, name=schematic.name or (type(schematic)=="string" and schematic),
|
||||
pos=ppos, size=size, yoffset=yoffset, y_min=y_min, y_max=y_max,
|
||||
schematic=schematic, rotation=rotation, replacements=replacements, force_placement=force_placement,
|
||||
prepare=prepare, pr=pr,
|
||||
after_placement_callback=after_placement_callback, callback_param=callback_param
|
||||
})
|
||||
end
|
||||
|
||||
-- Call on_construct on pos.
|
||||
-- Useful to init chests from formspec.
|
||||
local function init_node_construct(pos)
|
||||
-- Call all on_construct handlers
|
||||
-- also called from mcl_villages for job sites
|
||||
function mcl_structures.init_node_construct(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
if def and def.on_construct then
|
||||
def.on_construct(pos)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
local def = node and minetest.registered_nodes[node.name]
|
||||
if def and def.on_construct then def.on_construct(pos) end
|
||||
end
|
||||
|
||||
-- Find nodes to call on_construct handlers for
|
||||
function mcl_structures.construct_nodes(p1,p2,nodes)
|
||||
local nn = minetest.find_nodes_in_area(p1,p2,nodes)
|
||||
for _,p in pairs(nn) do mcl_structures.init_node_construct(p) end
|
||||
end
|
||||
mcl_structures.init_node_construct = init_node_construct
|
||||
|
||||
function mcl_structures.fill_chests(p1,p2,loot,pr)
|
||||
for it,lt in pairs(loot) do
|
||||
|
@ -100,123 +212,6 @@ function mcl_structures.fill_chests(p1,p2,loot,pr)
|
|||
end
|
||||
end
|
||||
|
||||
local function generate_loot(pos, def, pr)
|
||||
local hl = def.sidelen
|
||||
local p1 = vector.offset(pos,-hl,-hl,-hl)
|
||||
local p2 = vector.offset(pos,hl,hl,hl)
|
||||
if def.loot then mcl_structures.fill_chests(p1,p2,def.loot,pr) end
|
||||
end
|
||||
|
||||
function mcl_structures.construct_nodes(p1,p2,nodes)
|
||||
local nn=minetest.find_nodes_in_area(p1,p2,nodes)
|
||||
for _,p in pairs(nn) do
|
||||
mcl_structures.init_node_construct(p)
|
||||
end
|
||||
end
|
||||
|
||||
local function construct_nodes(pos,def,pr)
|
||||
return mcl_structures.construct_nodes(vector.offset(pos,-def.sidelen/2,0,-def.sidelen/2),vector.offset(pos,def.sidelen/2,def.sidelen,def.sidelen/2),def.construct_nodes)
|
||||
end
|
||||
|
||||
|
||||
function mcl_structures.find_lowest_y(pp)
|
||||
local y = 31000
|
||||
for _,p in pairs(pp) do
|
||||
if p.y < y then y = p.y end
|
||||
end
|
||||
return y
|
||||
end
|
||||
|
||||
function mcl_structures.find_highest_y(pp)
|
||||
local y = -31000
|
||||
for _,p in pairs(pp) do
|
||||
if p.y > y then y = p.y end
|
||||
end
|
||||
return y
|
||||
end
|
||||
|
||||
local function smooth_cube(nn,pos,plane,amnt)
|
||||
local r = {}
|
||||
local amnt = amnt or 9
|
||||
table.sort(nn,function(a, b)
|
||||
if false or plane then
|
||||
return vector.distance(vector.new(pos.x,0,pos.z), vector.new(a.x,0,a.z)) < vector.distance(vector.new(pos.x,0,pos.z), vector.new(b.x,0,b.z))
|
||||
else
|
||||
return vector.distance(pos, a) < vector.distance(pos, b)
|
||||
end
|
||||
end)
|
||||
for i=1,math.max(1,#nn-amnt) do table.insert(r,nn[i]) end
|
||||
return r
|
||||
end
|
||||
|
||||
local function find_ground(pos,nn,gn)
|
||||
local r = 0
|
||||
for _,v in pairs(nn) do
|
||||
local p=vector.new(v)
|
||||
repeat
|
||||
local n = minetest.get_node(p).name
|
||||
p = vector.offset(p,0,-1,0)
|
||||
until not n or n == "mcl_core:bedrock" or n == "ignore" or n == gn
|
||||
--minetest.log(tostring(pos.y - p.y))
|
||||
if pos.y - p.y > r then r = pos.y - p.y end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local function get_foundation_nodes(ground_p1,ground_p2,pos,sidelen,node_stone)
|
||||
local replace = {"air","group:liquid","mcl_core:snow","group:tree","group:leaves","group:plant","grass_block","group:dirt"}
|
||||
local depth = find_ground(pos,minetest.find_nodes_in_area(ground_p1,ground_p2,replace),node_stone)
|
||||
local nn = smooth_cube(minetest.find_nodes_in_area(vector.offset(ground_p1,0,-1,0),vector.offset(ground_p2,0,-depth,0),replace),vector.offset(pos,0,-depth,0),true,sidelen * 64)
|
||||
local stone = {}
|
||||
local filler = {}
|
||||
local top = {}
|
||||
local dust = {}
|
||||
for l,v in pairs(nn) do
|
||||
if v.y == ground_p1.y - 1 then
|
||||
table.insert(filler,v)
|
||||
table.insert(top,vector.offset(v,0,1,0))
|
||||
table.insert(dust,vector.offset(v,0,2,0))
|
||||
elseif v.y < ground_p1.y -1 and v.y > ground_p2.y -4 then table.insert(filler,v)
|
||||
elseif v.y < ground_p2.y - 3 and v.y > ground_p2.y -5 then
|
||||
if math.random(3) == 1 then
|
||||
table.insert(filler,v)
|
||||
else
|
||||
table.insert(stone,v)
|
||||
end
|
||||
else
|
||||
table.insert(stone,v)
|
||||
end
|
||||
end
|
||||
return stone,filler,top,dust
|
||||
end
|
||||
|
||||
local function foundation(ground_p1,ground_p2,pos,sidelen)
|
||||
local node_stone = "mcl_core:stone"
|
||||
local node_filler = "mcl_core:dirt"
|
||||
local node_top = "mcl_core:dirt_with_grass" or minetest.get_node(ground_p1).name
|
||||
local node_dust = nil
|
||||
|
||||
if mg_name ~= "v6" then
|
||||
local b = minetest.registered_biomes[minetest.get_biome_name(minetest.get_biome_data(pos).biome)]
|
||||
--minetest.log(dump(b.node_top))
|
||||
if b then
|
||||
if b.node_top then node_top = b.node_top end
|
||||
if b.node_filler then node_filler = b.node_filler end
|
||||
if b.node_stone then node_stone = b.node_stone end
|
||||
if b.node_dust then node_dust = b.node_dust end
|
||||
end
|
||||
end
|
||||
|
||||
local stone,filler,top,dust = get_foundation_nodes(ground_p1,ground_p2,pos,sidelen,node_stone)
|
||||
minetest.bulk_set_node(top,{name=node_top},node_stone)
|
||||
|
||||
if node_dust then
|
||||
minetest.bulk_set_node(dust,{name=node_dust})
|
||||
end
|
||||
minetest.bulk_set_node(filler,{name=node_filler})
|
||||
minetest.bulk_set_node(stone,{name=node_stone})
|
||||
end
|
||||
|
||||
function mcl_structures.spawn_mobs(mob,spawnon,p1,p2,pr,n,water)
|
||||
n = n or 1
|
||||
local sp = {}
|
||||
|
@ -243,98 +238,148 @@ function mcl_structures.spawn_mobs(mob,spawnon,p1,p2,pr,n,water)
|
|||
end
|
||||
|
||||
function mcl_structures.place_structure(pos, def, pr, blockseed, rot)
|
||||
if not def then return end
|
||||
if not rot then rot = "random" end
|
||||
if not def then return end
|
||||
local log_enabled = logging and not def.terrain_feature
|
||||
local y_offset = 0
|
||||
if type(def.y_offset) == "function" then
|
||||
y_offset = def.y_offset(pr)
|
||||
elseif def.y_offset then
|
||||
y_offset = def.y_offset
|
||||
end
|
||||
local pp = vector.offset(pos,0,y_offset,0)
|
||||
if def.solid_ground and def.sidelen then
|
||||
local ground_p1 = vector.offset(pos,-def.sidelen/2,-1,-def.sidelen/2)
|
||||
local ground_p2 = vector.offset(pos,def.sidelen/2,-1,def.sidelen/2)
|
||||
|
||||
local solid = minetest.find_nodes_in_area(ground_p1,ground_p2,{"group:solid"})
|
||||
if #solid < ( def.sidelen * def.sidelen ) then
|
||||
if def.make_foundation then
|
||||
foundation(vector.offset(pos,-def.sidelen/2 - 3,-1,-def.sidelen/2 - 3),vector.offset(pos,def.sidelen/2 + 3,-1,def.sidelen/2 + 3),pos,def.sidelen)
|
||||
else
|
||||
if log_enabled then
|
||||
minetest.log("warning","[mcl_structures] "..def.name.." at "..minetest.pos_to_string(pp).." not placed. No solid ground.")
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
-- currently only used by fallen_tree, to check for sufficient empty space to fall
|
||||
if def.on_place and not def.on_place(pos,def,pr,blockseed) then
|
||||
if log_enabled then
|
||||
minetest.log("warning","[mcl_structures] "..def.name.." at "..minetest.pos_to_string(pp).." not placed. Conditions not satisfied.")
|
||||
minetest.log("warning","[mcl_structures] "..def.name.." at "..minetest.pos_to_string(pos).." not placed. on_place conditions not satisfied.")
|
||||
end
|
||||
return false
|
||||
end
|
||||
if def.filenames then
|
||||
if #def.filenames <= 0 then return false end
|
||||
local r = pr:next(1,#def.filenames)
|
||||
local file = def.filenames[r]
|
||||
if file then
|
||||
local rot = rotations[pr:next(1,#rotations)]
|
||||
local ap = function(pos,def,pr,blockseed) end
|
||||
|
||||
if def.daughters then
|
||||
ap = function(pos,def,pr,blockseed)
|
||||
for _,d in pairs(def.daughters) do
|
||||
local p = vector.add(pos,d.pos)
|
||||
local rot = d.rot or 0
|
||||
mcl_structures.place_schematic(p, d.files[pr:next(1,#d.files)], rot, nil, true, "place_center_x,place_center_z",function()
|
||||
if def.loot then generate_loot(pp,def,pr,blockseed) end
|
||||
if def.construct_nodes then construct_nodes(pp,def,pr,blockseed) end
|
||||
if def.after_place then
|
||||
def.after_place(pos,def,pr)
|
||||
end
|
||||
end,pr)
|
||||
-- Apply vertical offset for schematic
|
||||
local yoffset = (type(def.y_offset) == "function" and def.y_offset(pr)) or def.y_offset or 0
|
||||
if def.schematics and #def.schematics > 0 then
|
||||
local schematic = def.schematics[pr:next(1,#def.schematics)]
|
||||
rot = mcl_structures.parse_rotation(rot or "random", pr)
|
||||
if not def.daughters then
|
||||
mcl_structures.place_schematic(pos, yoffset, def.y_min, def.y_max, schematic, rot, def.replacements, def.force_placement, "place_center_x,place_center_z", def.prepare, pr,
|
||||
function(p1, p2, size, rotation)
|
||||
if def.loot then mcl_structures.fill_chests(p1,p2,def.loot,pr) end
|
||||
if def.construct_nodes then mcl_structures.construct_nodes(p1,p2,def.construct_nodes) end
|
||||
if def.after_place then def.after_place(pos,def,pr,p1,p2,size,rotation) end
|
||||
if log_enabled then
|
||||
minetest.log("action", "[mcl_structures] "..def.name.." spawned at "..minetest.pos_to_string(pos))
|
||||
end
|
||||
end
|
||||
elseif def.after_place then
|
||||
ap = def.after_place
|
||||
end
|
||||
mcl_structures.place_schematic(pp, file, rot, def.replacements, true, "place_center_x,place_center_z",function(p1, p2, size, rotation)
|
||||
if not def.daughters then
|
||||
if def.loot then generate_loot(pp,def,pr,blockseed) end
|
||||
if def.construct_nodes then construct_nodes(pp,def,pr,blockseed) end
|
||||
end
|
||||
return ap(pp,def,pr,blockseed,p1,p2,size,rotation)
|
||||
end,pr)
|
||||
if log_enabled then
|
||||
minetest.log("action","[mcl_structures] "..def.name.." placed at "..minetest.pos_to_string(pp))
|
||||
end
|
||||
return true
|
||||
end)
|
||||
else -- currently only nether bulwarks + nether outpost with bridges?
|
||||
-- FIXME: this really needs to be run in a single emerge!
|
||||
mcl_structures.place_schematic(pos, yoffset, def.y_min, def.y_max, schematic, rot, def.replacements, def.force_placement, "place_center_x,place_center_z", def.prepare, pr,
|
||||
function(p1, p2, size, rotation)
|
||||
for i,d in pairs(def.daughters) do
|
||||
local ds = d.files[pr:next(1,#d.files)]
|
||||
-- Daughter schematics are not loaded yet.
|
||||
if ds and not ds.size then
|
||||
ds = loadstring(minetest.serialize_schematic(ds, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic")()
|
||||
end
|
||||
-- FIXME: apply centering, apply parent rotation.
|
||||
local rot = d.rot or 0
|
||||
local dsize = mcl_structures.size_rotated(ds.size, rot)
|
||||
local p = vector.new(math.floor((p1.x+p2.x)*0.5) + d.pos.x - math.floor((dsize.x-1)*0.5), p1.y + (yoffset or 0) + d.pos.y, math.floor((p1.z+p2.z)*0.5) + d.pos.z - math.floor((dsize.z-1)*0.5))
|
||||
local callback = nil
|
||||
if i == #def.daughters then
|
||||
callback = function()
|
||||
-- Note: deliberately pos, p1 and p2 from the parent, as these are calls to the parent.
|
||||
if def.loot then mcl_structures.fill_chests(p1,p2,def.loot,pr) end
|
||||
if def.construct_nodes then mcl_structures.construct_nodes(p1,p2,def.construct_nodes) end
|
||||
if def.after_place then def.after_place(pos,def,pr,p1,p2,size,rotation) end
|
||||
if log_enabled then
|
||||
minetest.log("action", "[mcl_structures] "..def.name.." spawned at "..minetest.pos_to_string(pos))
|
||||
end
|
||||
end
|
||||
end
|
||||
mcl_structures.place_schematic(p, yoffset, d.y_min or def.y_min, d.y_max or def.y_max, ds, rot, nil, true, "place_center_x,place_center_y", d.prepare, pr, callback)
|
||||
end
|
||||
end)
|
||||
end
|
||||
elseif def.place_func and def.place_func(pp,def,pr,blockseed) then
|
||||
if not def.after_place or ( def.after_place and def.after_place(pp,def,pr,blockseed) ) then
|
||||
if def.loot then generate_loot(pp,def,pr,blockseed) end
|
||||
if def.construct_nodes then construct_nodes(pp,def,pr,blockseed) end
|
||||
if log_enabled then
|
||||
minetest.log("verbose", "[mcl_structures] "..def.name.." to be placed at "..minetest.pos_to_string(pos))
|
||||
end
|
||||
return true
|
||||
end
|
||||
if not def.place_func then
|
||||
minetest.log("warning","[mcl_structures] no schematics and no place_func for schematic "..def.name)
|
||||
return false
|
||||
end
|
||||
if def.solid_ground and def.sidelen and not def.prepare then
|
||||
-- TODO: this assumes place_center, make padding configurable, use actual size?
|
||||
local ground_p1 = vector.offset(pos,-math.floor(def.sidelen/2),-1,-math.floor(def.sidelen/2))
|
||||
local ground_p2 = vector.offset(ground_p1,def.sidelen-1,0,def.sidelen-1)
|
||||
local solid = minetest.find_nodes_in_area(ground_p1,ground_p2,{"group:solid"})
|
||||
if #solid < def.sidelen * def.sidelen then
|
||||
if log_enabled then
|
||||
minetest.log("action","[mcl_structures] "..def.name.." placed at "..minetest.pos_to_string(pp))
|
||||
minetest.log("warning", "[mcl_structures] "..def.name.." at "..minetest.pos_to_string(pos).." not placed. No solid ground.")
|
||||
end
|
||||
return true
|
||||
return false
|
||||
end
|
||||
end
|
||||
if log_enabled then
|
||||
minetest.log("warning","[mcl_structures] placing "..def.name.." failed at "..minetest.pos_to_string(pos))
|
||||
local pp = yoffset ~= 0 and vector.offset(pos, 0, yoffset, 0) or pos
|
||||
if def.place_func and def.place_func(pp,def,pr,blockseed) then
|
||||
if not def.after_place or (def.after_place and def.after_place(pp,def,pr,blockseed)) then
|
||||
if def.prepare then
|
||||
minetest.log("warning", "[mcl_structures] needed prepare for "..def.name.." placed at "..minetest.pos_to_string(pp).." but did not have size information")
|
||||
end
|
||||
if def.sidelen then
|
||||
local p1, p2 = vector.offset(pos,-def.sidelen,-def.sidelen,-def.sidelen), vector.offset(pos,def.sidelen,def.sidelen,def.sidelen)
|
||||
if def.loot then mcl_structures.fill_chests(p1,p2,def.loot,pr) end
|
||||
if def.construct_nodes then mcl_structures.construct_nodes(p1,p2,def.construct_nodes) end
|
||||
end
|
||||
if log_enabled then
|
||||
minetest.log("action","[mcl_structures] "..def.name.." placed at "..minetest.pos_to_string(pp))
|
||||
end
|
||||
return true
|
||||
else
|
||||
minetest.log("warning","[mcl_structures] after_place failed for schematic "..def.name)
|
||||
return false
|
||||
end
|
||||
elseif log_enabled then
|
||||
minetest.log("warning","[mcl_structures] place_func failed for schematic "..def.name)
|
||||
end
|
||||
end
|
||||
|
||||
local EMPTY_SCHEMATIC = { size = {x = 0, y = 0, z = 0}, data = { } }
|
||||
function mcl_structures.register_structure(name,def,nospawn) --nospawn means it will not be placed by mapgen decoration mechanism
|
||||
if mcl_structures.is_disabled(name) then return end
|
||||
flags = def.flags or "place_center_x, place_center_z, force_placement"
|
||||
def.name = name
|
||||
if not nospawn and def.place_on then
|
||||
def.prepare = def.prepare or (type(def.make_foundation) == table and def.make_foundation)
|
||||
def.flags = def.flags or "place_center_x, place_center_z, force_placement"
|
||||
if def.filenames then
|
||||
if #def.filenames == 0 then
|
||||
minetest.log("warning","[mcl_structures] schematic "..name.." has an empty list of filenames.")
|
||||
end
|
||||
def.schematics = def.schematics or {}
|
||||
for _, filename in ipairs(def.filenames) do
|
||||
if not mcl_util.file_exists(filename) then
|
||||
minetest.log("warning","[mcl_structures] schematic "..name.." is missing file "..tostring(filename))
|
||||
else
|
||||
|
||||
-- load, and ensure we have size information
|
||||
local s = nil --minetest.read_schematic(filename)
|
||||
if not s or not s.size then
|
||||
s = loadstring(minetest.serialize_schematic(filename, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return schematic")()
|
||||
end
|
||||
if not s then
|
||||
minetest.log("warning", "[mcl_structures] failed to load schematic "..tostring(filename))
|
||||
elseif not s.size then
|
||||
minetest.log("warning", "[mcl_structures] no size information for schematic "..tostring(filename))
|
||||
else
|
||||
if logging then
|
||||
minetest.log("verbose", "[mcl_structures] loaded schematic "..tostring(filename).." size "..minetest.pos_to_string(s.size))
|
||||
end
|
||||
if not s.name then s.name = name or filename end
|
||||
table.insert(def.schematics, s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not def.noise_params and def.chunk_probability and not def.fill_ratio then
|
||||
def.fill_ratio = 1.1/80/80 -- 1 per chunk, controlled by chunk probability only
|
||||
end
|
||||
mcl_structures.registered_structures[name] = def
|
||||
if nospawn then return end -- ice column, boulder
|
||||
if def.place_on then
|
||||
minetest.register_on_mods_loaded(function() --make sure all previous decorations and biomes have been registered
|
||||
def.deco = minetest.register_decoration({
|
||||
def.deco = mcl_mapgen_core.register_decoration({
|
||||
name = "mcl_structures:deco_"..name,
|
||||
priority = def.priority or (def.terrain_feature and 900) or 100, -- run before regular decorations
|
||||
deco_type = "schematic",
|
||||
|
@ -342,20 +387,19 @@ function mcl_structures.register_structure(name,def,nospawn) --nospawn means it
|
|||
place_on = def.place_on,
|
||||
spawn_by = def.spawn_by,
|
||||
num_spawn_by = def.num_spawn_by,
|
||||
sidelen = 80,
|
||||
sidelen = 80, -- no def.sidelen subdivisions for now
|
||||
fill_ratio = def.fill_ratio,
|
||||
noise_params = def.noise_params,
|
||||
flags = flags,
|
||||
flags = def.flags,
|
||||
biomes = def.biomes,
|
||||
y_max = def.y_max,
|
||||
y_min = def.y_min
|
||||
})
|
||||
def.deco_id = minetest.get_decoration_id("mcl_structures:deco_"..name)
|
||||
minetest.set_gen_notify({decoration=true}, { def.deco_id })
|
||||
--catching of gennotify happens in mcl_mapgen_core
|
||||
}, function()
|
||||
def.deco_id = minetest.get_decoration_id("mcl_structures:deco_"..name)
|
||||
minetest.set_gen_notify({decoration=true}, { def.deco_id })
|
||||
end)
|
||||
end)
|
||||
end
|
||||
mcl_structures.registered_structures[name] = def
|
||||
end
|
||||
|
||||
local structure_spawns = {}
|
||||
|
@ -417,3 +461,4 @@ mcl_mapgen_core.register_generator("structures", nil, function(minp, maxp, block
|
|||
return false, false, false
|
||||
end, 100, true)
|
||||
end)
|
||||
|
||||
|
|
|
@ -34,13 +34,11 @@ end
|
|||
|
||||
mcl_structures.register_structure("desert_temple",{
|
||||
place_on = {"group:sand"},
|
||||
fill_ratio = 0.01,
|
||||
flags = "place_center_x, place_center_z",
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
sidelen = 18,
|
||||
y_offset = -12,
|
||||
chunk_probability = 300,
|
||||
chunk_probability = 8,
|
||||
y_max = mcl_vars.mg_overworld_max,
|
||||
y_min = 1,
|
||||
biomes = { "Desert" },
|
||||
|
|
|
@ -17,10 +17,9 @@ end
|
|||
|
||||
mcl_structures.register_structure("end_shipwreck",{
|
||||
place_on = {"mcl_end:end_stone"},
|
||||
fill_ratio = 0.001,
|
||||
flags = "place_center_x, place_center_z, all_floors",
|
||||
y_offset = function(pr) return pr:next(-50,-20) end,
|
||||
chunk_probability = 800,
|
||||
chunk_probability = 25,
|
||||
--y_max = mcl_vars.mg_end_max,
|
||||
--y_min = mcl_vars.mg_end_min -100,
|
||||
biomes = { "End", "EndHighlands", "EndMidlands", "EndBarrens", "EndSmallIslands" },
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
local AIR = {name = "air"}
|
||||
local abs = math.abs
|
||||
local max = math.max
|
||||
|
||||
-- fairly strict: air, ignore, or no_paths marker
|
||||
local function is_air(node)
|
||||
return not node or node.name == "air" or node.name == "ignore" or node.name == "mcl_villages:no_paths"
|
||||
end
|
||||
-- check if a node is walkable (solid), but not tree/leaves
|
||||
local function is_solid_not_tree(node)
|
||||
if not node or node.name == "air" or node.name == "ignore" or node.name == "mcl_villages:no_paths" then return false end
|
||||
local meta = minetest.registered_items[node.name]
|
||||
local groups = meta and meta.groups
|
||||
return meta and meta.walkable and not (groups and (groups["deco_block"] or groups["tree"] or groups["leaves"] or groups["plant"]))
|
||||
end
|
||||
-- check if a node is walkable (solid), but not tree/leaves or buildungs
|
||||
local function is_solid_not_tree_or_building(node)
|
||||
if not node or node.name == "air" or node.name == "ignore" or node.name == "mcl_villages:no_paths" then return false end
|
||||
local meta = minetest.registered_items[node.name]
|
||||
local groups = meta and meta.groups
|
||||
return meta and meta.walkable and not (groups and (groups["deco_block"] or groups["tree"] or groups["leaves"] or groups["plant"] or groups["building_block"]))
|
||||
end
|
||||
-- check if a node is tree
|
||||
local function is_tree(node)
|
||||
if not node or node.name == "air" or node.name == "ignore" or node.name == "mcl_villages:no_paths" then return false end
|
||||
local meta = minetest.registered_items[node.name]
|
||||
local groups = meta and meta.groups
|
||||
return groups and (groups["tree"] or groups["leaves"])
|
||||
end
|
||||
-- replace a non-solid node, optionally also "additional"
|
||||
local function make_solid(lvm, cp, with, additional)
|
||||
local cur = lvm:get_node_at(cp)
|
||||
if not is_solid_not_tree(cur) or (additional and cur.name == additional.name) then
|
||||
lvm:set_node_at(cp, with)
|
||||
end
|
||||
end
|
||||
local function excavate(lvm,xi,yi,zi,pr,keep_trees)
|
||||
local pos, n, c = vector.new(xi,yi,zi), nil, 0
|
||||
local node = lvm:get_node_at(pos)
|
||||
if is_air(node) then return false end -- already empty, nothing to do
|
||||
if keep_trees and is_tree(node) then return false end
|
||||
pos.y = pos.y-1
|
||||
if not is_air(lvm:get_node_at(pos)) then return false end -- below is solid, do not clear above anymore
|
||||
-- count empty nodes below otherwise
|
||||
for x = xi-1,xi+1 do
|
||||
for z = zi-1,zi+1 do
|
||||
pos.x, pos.z = x, z
|
||||
if is_air(lvm:get_node_at(pos)) then c = c + 1 end
|
||||
end
|
||||
end
|
||||
-- try to completely remove trees overhead
|
||||
-- stop randomly depending on fill, to narrow down the caves
|
||||
if not keep_trees and not is_tree(node) and (pr:next(0,1e9)/1e9)^2 > c/9.1 then return false end
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), AIR)
|
||||
return true -- modified
|
||||
end
|
||||
function mcl_structures.clearance(lvm, px, py, pz, sx, sy, sz, corners, surface_mat, pr)
|
||||
corners = corners or 0
|
||||
local wx2, wz2 = max(sx - corners, 1)^-2*2, max(sz - corners, 1)^-2*2
|
||||
local cx, cz = px + sx * 0.5 - 0.5, pz + sz * 0.5 - 0.5
|
||||
-- excavate the needed volume and some headroom
|
||||
for xi = px,px+sx-1 do
|
||||
local dx2 = (cx-xi)^2*wx2
|
||||
for zi = pz,pz+sz-1 do
|
||||
local dz2 = (cz-zi)^2*wz2
|
||||
if dx2+dz2 <= 1 then
|
||||
lvm:set_node_at(vector.new(xi, py, zi), AIR)
|
||||
local n = lvm:get_node_at(vector.new(xi, py-1, zi))
|
||||
if n and n.name ~= surface_mat.name and is_solid_not_tree_or_building(n) then
|
||||
lvm:set_node_at(vector.new(xi, py-1, zi), surface_mat)
|
||||
end
|
||||
-- py+1 to py+4 are filled wider below, this is the top of the building only
|
||||
for yi = py+5,py+sy do
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), AIR)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- slightly widen the cave above, to make easier to enter for mobs
|
||||
for xi = px-1,px+sx do
|
||||
local dx2 = max(abs(cx-xi)-1,0)^2*wx2
|
||||
for zi = pz-1,pz+sz do
|
||||
local dz2 = max(abs(cz-zi)-1,0)^2*wz2
|
||||
if dx2+dz2 <= 1 then
|
||||
for yi = py+1,py+4 do
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), AIR)
|
||||
end
|
||||
local n = lvm:get_node_at(vector.new(xi, py, zi))
|
||||
for yi = py,py-1,-1 do
|
||||
local n = lvm:get_node_at(vector.new(xi, yi, zi))
|
||||
if is_tree(n) then
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), AIR)
|
||||
else
|
||||
if n and n.name ~= surface_mat.name and is_solid_not_tree_or_building(n) then
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), surface_mat)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- some extra gaps for entry
|
||||
for xi = px-2,px+sx+1 do
|
||||
local dx2 = max(abs(cx-xi)-2,0)^2*wx2
|
||||
for zi = pz-2,pz+sz+1 do
|
||||
local dz2 = max(abs(cz-zi)-2,0)^2*wz2
|
||||
if dx2+dz2 <= 1 and pr:next(1,4) == 1 then
|
||||
for yi = py+2,py+4 do
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), AIR)
|
||||
end
|
||||
local n = lvm:get_node_at(vector.new(xi, py+1, zi))
|
||||
for yi = py+1,py-1,-1 do
|
||||
local n = lvm:get_node_at(vector.new(xi, yi, zi))
|
||||
if is_tree(n) then
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), AIR)
|
||||
else
|
||||
if n and n.name ~= surface_mat.name and is_solid_not_tree_or_building(n) then
|
||||
lvm:set_node_at(vector.new(xi, py+1, zi), surface_mat)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- cave some additional area overhead, try to make it interesting though
|
||||
local min_clear, max_clear = sy+5, sy*2+5 -- FIXME: make parameters
|
||||
for yi = py+2,py+max_clear do
|
||||
local dy2 = (py-yi)^2*0.025
|
||||
local active = false
|
||||
for xi = px-2,px+sx+1 do
|
||||
local dx2 = max(abs(cx-xi)-2,0)^2*wx2
|
||||
for zi = pz-2,pz+sz+1 do
|
||||
local dz2 = max(abs(cz-zi)-2,0)^2*wz2
|
||||
local keep_trees = (xi<px or xi>=px+sx) or (zi<pz or zi>=pz+sz) -- TODO make configurable?
|
||||
if dx2+dz2+dy2 <= 1 and excavate(lvm,xi,yi,zi,pr,keep_trees) then active = true end
|
||||
end
|
||||
end
|
||||
if not active and yi > py+min_clear then break end
|
||||
end
|
||||
end
|
||||
-- TODO: allow controlling the random depth?
|
||||
-- TODO: add support for dust_mat (snow)
|
||||
local function grow_foundation(lvm,xi,yi,zi,pr,surface_mat,platform_mat,stone_mat)
|
||||
local pos, n, c = vector.new(xi,yi,zi), nil, 0
|
||||
if is_solid_not_tree(lvm:get_node_at(pos)) then return false end -- already solid, nothing to do
|
||||
pos.y = pos.y+1
|
||||
local cur = lvm:get_node_at(pos)
|
||||
if not is_solid_not_tree(cur) then return false end -- above is empty, do not fill below
|
||||
if cur and cur.name and cur.name ~= surface_mat.name then platform_mat = cur end
|
||||
if pr:next(1,5) == 5 then -- randomly switch to stone sometimes
|
||||
platform_mat = stone_mat
|
||||
end
|
||||
-- count solid nodes above otherwise
|
||||
for x = xi-1,xi+1 do
|
||||
for z = zi-1,zi+1 do
|
||||
pos.x, pos.z = x, z
|
||||
if is_solid_not_tree(lvm:get_node_at(pos)) then c = c + 1 end
|
||||
end
|
||||
end
|
||||
-- stop randomly depending on fill, to narrow down the foundation
|
||||
if (pr:next(0,1e9)/1e9)^2 > c/9.1 then return false end
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), platform_mat)
|
||||
return true -- modified
|
||||
end
|
||||
-- generate a foundations around px,py,pz with size sx,sy,sz (sy < 0)
|
||||
-- TODO: add support for dust_mat (snow)
|
||||
-- Rounding: we model an ellipse. At zero rounding, we want the line go through the corner, at sx/2, sz/2.
|
||||
-- For this, we need to make ellipse sized 2a=sqrt(2)*sx, 2b=sqrt(2)*sz,
|
||||
-- Which yields a = sx/sqrt(2), b=sz/sqrt(2) and a^2=sx^2*0.5, b^2=sz^2*0.5
|
||||
-- To get corners, we decrease a and b by approx. corners each
|
||||
-- The ellipse condition dx^2/a^2+dz^2/b^2 <= 1 then yields dx^2/(sx^2*0.5) + dz^2/(sz^2*0.5) <= 1
|
||||
-- We use wx2=(sx^2)^-2*2, wz2=(sz^2)^-2*2 and then dx^2*wx2+dz^2*wz2 <= 1
|
||||
function mcl_structures.foundation(lvm, px, py, pz, sx, depth, sz, corners, surface_mat, platform_mat, stone_mat, pr)
|
||||
corners = corners or 0
|
||||
local wx2, wz2 = max(sx - corners, 1)^-2*2, max(sz - corners, 1)^-2*2
|
||||
local cx, cz = px + sx * 0.5 - 0.5, pz + sz * 0.5 - 0.5
|
||||
-- generate a baseplate
|
||||
for xi = px,px+sx-1 do
|
||||
local dx2 = (cx-xi)^2*wx2
|
||||
for zi = pz,pz+sz-1 do
|
||||
local dz2 = (cz-zi)^2*wz2
|
||||
if dx2+dz2 <= 1 then
|
||||
lvm:set_node_at(vector.new(xi, py, zi), surface_mat)
|
||||
make_solid(lvm, vector.new(xi, py-1, zi), platform_mat)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- slightly widen the baseplate below, to make easier to enter for mobs
|
||||
if corners and corners > 0 then
|
||||
for xi = px-1,px+sx do
|
||||
local dx2 = max(abs(cx-xi)-1,0)^2*wx2
|
||||
-- TODO: compute the z value ranges directly?
|
||||
for zi = pz-1,pz+sz do
|
||||
local dz2 = max(abs(cz-zi)-1,0)^2*wz2
|
||||
if dx2+dz2 <= 1 then
|
||||
make_solid(lvm, vector.new(xi, py-1, zi), surface_mat)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
for xi = px+1,px+sx-1-1 do
|
||||
make_solid(lvm, vector.new(xi, py-1, pz-1), surface_mat, platform_mat)
|
||||
make_solid(lvm, vector.new(xi, py-1, pz), platform_mat)
|
||||
make_solid(lvm, vector.new(xi, py-1, pz+sz-1), platform_mat)
|
||||
make_solid(lvm, vector.new(xi, py-1, pz+sz), surface_mat, platform_mat)
|
||||
end
|
||||
for zi = pz+1,pz+sz-1-1 do
|
||||
make_solid(lvm, vector.new(px-1, py-1, zi), surface_mat, platform_mat)
|
||||
make_solid(lvm, vector.new(px, py-1, zi), platform_mat)
|
||||
make_solid(lvm, vector.new(px+sx-1, py-1, zi), platform_mat)
|
||||
make_solid(lvm, vector.new(px+sx, py-1, zi), surface_mat, platform_mat)
|
||||
end
|
||||
-- make some additional steps, along both x sides
|
||||
for xi = px+1,px+sx-2 do
|
||||
local cp = vector.new(xi, py-3, pz-1)
|
||||
if is_solid_not_tree(lvm:get_node_at(cp)) then
|
||||
cp = vector.new(xi, py-2, pz-1)
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
cp.z = pz-2
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
end
|
||||
local cp = vector.new(xi, py-3, pz+sz)
|
||||
if is_solid_not_tree(lvm:get_node_at(cp)) then
|
||||
cp = vector.new(xi, py-2, pz+sz)
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
cp.z = pz + sz + 1
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
end
|
||||
end
|
||||
-- make some additional steps, along both z sides
|
||||
for zi = pz+1,pz+sz-2 do
|
||||
local cp = vector.new(px-1, py-3, zi)
|
||||
if is_solid_not_tree(lvm:get_node_at(cp)) then
|
||||
cp = vector.new(px-1, py-2, zi)
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
cp.x = px-2
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
end
|
||||
local cp = vector.new(px+sx, py-3, zi)
|
||||
if is_solid_not_tree(lvm:get_node_at(cp)) then
|
||||
cp = vector.new(px+sx, py-2, zi)
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
cp.x = px+sx+1
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- construct additional baseplate below, also try to make it interesting
|
||||
for yi = py-2,py-20,-1 do
|
||||
local dy2 = (py-yi)^2*0.025
|
||||
local active = false
|
||||
for xi = px-1,px+sx do
|
||||
local dx2 = max(abs(cx-xi)-1,0)^2*wx2
|
||||
for zi = pz-1,pz+sz do
|
||||
local dz2 = max(abs(cz-zi)-1,0)^2*wz2
|
||||
if dx2+dy2+dz2 <= 1 then
|
||||
if grow_foundation(lvm,xi,yi,zi,pr,surface_mat,platform_mat,stone_mat) then active = true end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not active and yi < py + depth then break end
|
||||
end
|
||||
end
|
||||
-- return position and material of surface
|
||||
function mcl_structures.find_ground(lvm, pos)
|
||||
if not pos then return nil, nil end
|
||||
pos = vector.copy(pos)
|
||||
local cur = lvm:get_node_at(pos)
|
||||
if not cur or cur.name == "ignore" then
|
||||
local e1, e2 = lvm:get_emerged_area()
|
||||
minetest.log("warning","find_ground with invalid position (outside of emerged area?) at "..minetest.pos_to_string(pos)..": "..tostring(cur and cur.name).." area: "..minetest.pos_to_string(e1).." "..minetest.pos_to_string(e2))
|
||||
return nil
|
||||
end
|
||||
if is_solid_not_tree(cur) then -- find up
|
||||
local prev = cur
|
||||
while true do
|
||||
pos.y = pos.y + 1
|
||||
local cur = lvm:get_node_at(pos)
|
||||
if not cur or cur.name == "ignore" then
|
||||
minetest.log("action", "No ground, "..tostring(cur and cur.name).." over "..tostring(prev and prev.name).." at "..minetest.pos_to_string(pos))
|
||||
return nil
|
||||
end
|
||||
if not is_solid_not_tree(cur) then
|
||||
pos.y = pos.y - 1
|
||||
return pos, prev
|
||||
end
|
||||
prev = cur
|
||||
end
|
||||
else -- find down
|
||||
while true do
|
||||
pos.y = pos.y - 1
|
||||
local prev = cur
|
||||
local cur = lvm:get_node_at(pos)
|
||||
if not cur or cur.name == "ignore" then
|
||||
minetest.log("action", "No ground, "..tostring(cur and cur.name).." below "..tostring(prev and prev.name).." at "..minetest.pos_to_string(pos))
|
||||
return nil
|
||||
end
|
||||
if is_solid_not_tree(cur) then
|
||||
return pos, cur
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- find suitable height for a structure of this size
|
||||
-- @param lvm VoxelManip: to read data
|
||||
-- @param cpos vector: center
|
||||
-- @param size vector: area size
|
||||
-- @param tolerance number: maximum height difference allowed, default 8
|
||||
-- @return position, surface material
|
||||
function mcl_structures.find_level(lvm, cpos, size, tolerance)
|
||||
local cpos, surface_material = mcl_structures.find_ground(lvm, cpos)
|
||||
if not cpos then return nil, nil end
|
||||
local ys = {cpos.y}
|
||||
local pos = vector.offset(cpos, -math.floor((size.x-1)/2), 0, -math.floor((size.z-1)/2)) -- top left
|
||||
local pos_c = mcl_structures.find_ground(lvm, pos)
|
||||
if pos_c then table.insert(ys, pos_c.y) end
|
||||
local pos_c = mcl_structures.find_ground(lvm, vector.offset(pos, size.x-1, 0, 0))
|
||||
if pos_c then table.insert(ys, pos_c.y) end
|
||||
local pos_c = mcl_structures.find_ground(lvm, vector.offset(pos, 0, 0, size.z-1))
|
||||
if pos_c then table.insert(ys, pos_c.y) end
|
||||
local pos_c = mcl_structures.find_ground(lvm, vector.offset(pos, size.x-1, 0, size.z-1))
|
||||
if pos_c then table.insert(ys, pos_c.y) end
|
||||
table.sort(ys)
|
||||
-- well supported base, not too uneven?
|
||||
if #ys <= 4 or math.max(ys[#ys-1]-ys[1], ys[#ys]-ys[2]) > (tolerance or 8) then
|
||||
minetest.log("action", "[mcl_structures] ground too uneven: "..#ys.." positions, trimmed difference "..(#ys < 2 and "" or math.max(ys[#ys-1]-ys[1], ys[#ys]-ys[2])))
|
||||
return nil, nil
|
||||
end
|
||||
cpos.y = math.round(0.5*(ys[math.floor(#ys * 0.5)] + ys[math.ceil(#ys * 0.5)])) + 1 -- median, rounded, over surface
|
||||
return cpos, surface_material
|
||||
end
|
||||
|
|
@ -1,24 +1,11 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local S = minetest.get_translator(modname)
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
|
||||
function mcl_structures.generate_igloo_top(pos, pr)
|
||||
-- Furnace does ot work atm because apparently meta is not set. Need a bit of help with fixing this for furnaces, bookshelves, and brewing stands.
|
||||
local newpos = {x=pos.x,y=pos.y-2,z=pos.z}
|
||||
local path = modpath.."/schematics/mcl_structures_igloo_top.mts"
|
||||
local rotation = tostring(pr:next(0,3)*90)
|
||||
return mcl_structures.place_schematic(newpos, path, rotation, nil, true, nil, function()
|
||||
local p1 = vector.offset(pos,-5,-5,-5)
|
||||
local p2 = vector.offset(pos,5,5,5)
|
||||
mcl_structures.construct_nodes(p1,p2,{"mcl_furnaces:furnace","mcl_books:bookshelf"})
|
||||
end), rotation
|
||||
end
|
||||
local S = minetest.get_translator(modname)
|
||||
|
||||
local function spawn_mobs(p1,p2,vi,zv)
|
||||
local mc = minetest.find_nodes_in_area_under_air(p1,p2,{"mcl_core:stonebrickmossy"})
|
||||
if #mc == 2 then
|
||||
local vp = mc[1]
|
||||
local zp = mc[2]
|
||||
local vp, zp = mc[1], mc[2]
|
||||
if not vi and zv and zv:get_pos() and vector.distance(mc[1],zv:get_pos()) < 2 then
|
||||
vp = mc[2]
|
||||
elseif not zv and vi and vi:get_pos() and vector.distance(mc[2],vi:get_pos()) < 2 then
|
||||
|
@ -32,128 +19,112 @@ local function spawn_mobs(p1,p2,vi,zv)
|
|||
end
|
||||
end
|
||||
|
||||
function mcl_structures.generate_igloo_basement(pos, orientation, loot, pr)
|
||||
-- TODO: Add monster eggs
|
||||
local path = modpath.."/schematics/mcl_structures_igloo_basement.mts"
|
||||
mcl_structures.place_schematic(pos, path, orientation, nil, true, nil, function()
|
||||
local p1 = vector.offset(pos,-5,-5,-5)
|
||||
local p2 = vector.offset(pos,5,5,5)
|
||||
mcl_structures.fill_chests(p1,p2,loot,pr)
|
||||
mcl_structures.construct_nodes(p1,p2,{"mcl_brewing:stand_000","mcl_books:bookshelf"})
|
||||
spawn_mobs(p1,p2)
|
||||
end, pr)
|
||||
local function generate_igloo_basement(pos, orientation, loot, pr)
|
||||
end
|
||||
|
||||
function mcl_structures.generate_igloo(pos, def, pr)
|
||||
-- Place igloo
|
||||
local success, rotation = mcl_structures.generate_igloo_top(pos, pr)
|
||||
-- Place igloo basement with 50% chance
|
||||
local r = pr:next(1,2)
|
||||
if r == 1 then
|
||||
-- Select basement depth
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
--local buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10)
|
||||
local buffer
|
||||
if dim == "nether" then
|
||||
buffer = pos.y - (mcl_vars.mg_lava_nether_max + 10)
|
||||
elseif dim == "end" then
|
||||
buffer = pos.y - (mcl_vars.mg_end_min + 1)
|
||||
elseif dim == "overworld" then
|
||||
buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10)
|
||||
else
|
||||
return success
|
||||
end
|
||||
if buffer <= 19 then
|
||||
return success
|
||||
end
|
||||
local depth = pr:next(19, buffer)
|
||||
local bpos = {x=pos.x, y=pos.y-depth, z=pos.z}
|
||||
-- trapdoor position
|
||||
local tpos
|
||||
local dir, tdir
|
||||
if rotation == "0" then
|
||||
dir = {x=-1, y=0, z=0}
|
||||
tdir = {x=1, y=0, z=0}
|
||||
tpos = {x=pos.x+7, y=pos.y-2, z=pos.z+3}
|
||||
elseif rotation == "90" then
|
||||
dir = {x=0, y=0, z=-1}
|
||||
tdir = {x=0, y=0, z=-1}
|
||||
tpos = {x=pos.x+3, y=pos.y-2, z=pos.z+1}
|
||||
elseif rotation == "180" then
|
||||
dir = {x=1, y=0, z=0}
|
||||
tdir = {x=-1, y=0, z=0}
|
||||
tpos = {x=pos.x+1, y=pos.y-2, z=pos.z+3}
|
||||
elseif rotation == "270" then
|
||||
dir = {x=0, y=0, z=1}
|
||||
tdir = {x=0, y=0, z=1}
|
||||
tpos = {x=pos.x+3, y=pos.y-2, z=pos.z+7}
|
||||
else
|
||||
return success
|
||||
end
|
||||
local function set_brick(pos)
|
||||
local c = pr:next(1, 3) -- cracked chance
|
||||
local m = pr:next(1, 10) -- chance for monster egg
|
||||
local brick
|
||||
if m == 1 then
|
||||
if c == 1 then
|
||||
brick = "mcl_monster_eggs:monster_egg_stonebrickcracked"
|
||||
else
|
||||
brick = "mcl_monster_eggs:monster_egg_stonebrick"
|
||||
end
|
||||
local function generate_igloo(pos, def, pr)
|
||||
local path = modpath.."/schematics/mcl_structures_igloo_top.mts"
|
||||
local rotation = tostring(pr:next(0,3)*90)
|
||||
-- TODO: ymin, ymax
|
||||
mcl_structures.place_schematic(pos, -2, nil, nil, path, rotation, nil, true, nil, {padding=0, corners=2}, pr, function(p1, p2)
|
||||
mcl_structures.construct_nodes(p1, p2, {"mcl_furnaces:furnace","mcl_books:bookshelf"})
|
||||
-- Place igloo basement with 50% chance
|
||||
local r = 1--pr:next(1,2)
|
||||
if r == 1 then
|
||||
-- Select basement depth
|
||||
local dim = mcl_worlds.pos_to_dimension(pos)
|
||||
local buffer
|
||||
if dim == "nether" then
|
||||
buffer = pos.y - (mcl_vars.mg_lava_nether_max + 10)
|
||||
elseif dim == "end" then
|
||||
buffer = pos.y - (mcl_vars.mg_end_min + 1)
|
||||
elseif dim == "overworld" then
|
||||
buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10)
|
||||
else
|
||||
if c == 1 then
|
||||
brick = "mcl_core:stonebrickcracked"
|
||||
return true
|
||||
end
|
||||
if buffer <= 9 then return true end
|
||||
local depth = pr:next(9, buffer)
|
||||
local bpos = vector.new(pos.x, pos.y-depth, pos.z)
|
||||
-- trapdoor position and orientation
|
||||
local tpos, dir, tdir
|
||||
if rotation == "0" then
|
||||
dir = vector.new(-1, 0, 0)
|
||||
tdir = vector.new(1, 0, 0)
|
||||
tpos = vector.new(pos.x+7, pos.y, pos.z+3)
|
||||
elseif rotation == "90" then
|
||||
dir = vector.new(0, 0, -1)
|
||||
tdir = vector.new(0, 0, -1)
|
||||
tpos = vector.new(pos.x+3, pos.y, pos.z+1)
|
||||
elseif rotation == "180" then
|
||||
dir = vector.new(1, 0, 0)
|
||||
tdir = vector.new(-1, 0, 0)
|
||||
tpos = vector.new(pos.x+1, pos.y, pos.z+3)
|
||||
elseif rotation == "270" then
|
||||
dir = vector.new(0, 0, 1)
|
||||
tdir = vector.new(0, 0, 1)
|
||||
tpos = vector.new(pos.x+3, pos.y, pos.z+7)
|
||||
else
|
||||
minetest.log("bad rotation: "..tostring(rotation))
|
||||
return false
|
||||
end
|
||||
local function set_brick(pos)
|
||||
local c = pr:next(1, 3) -- cracked chance
|
||||
local m = pr:next(1, 10) -- chance for monster egg
|
||||
local brick
|
||||
if m == 1 then
|
||||
brick = (c == 1 and "mcl_monster_eggs:monster_egg_stonebrickcracked") or "mcl_monster_eggs:monster_egg_stonebrick"
|
||||
else
|
||||
brick = "mcl_core:stonebrick"
|
||||
brick = (c == 1 and "mcl_core:stonebrickcracked") or "mcl_core:stonebrick"
|
||||
end
|
||||
minetest.set_node(pos, {name=brick})
|
||||
end
|
||||
local real_depth = 0
|
||||
-- Check how deep we can actually dig
|
||||
for y=1, depth-5 do
|
||||
real_depth = real_depth + 1
|
||||
local node = minetest.get_node(vector.new(tpos.x, tpos.y-y, tpos.z))
|
||||
local def = node and minetest.registered_nodes[node.name]
|
||||
if not (def and def.walkable and def.liquidtype == "none" and def.is_ground_content) then
|
||||
bpos.y = tpos.y-y+1
|
||||
break
|
||||
end
|
||||
end
|
||||
minetest.set_node(pos, {name=brick})
|
||||
end
|
||||
local ladder_param2 = minetest.dir_to_wallmounted(tdir)
|
||||
local real_depth = 0
|
||||
-- Check how deep we can actuall dig
|
||||
for y=1, depth-5 do
|
||||
real_depth = real_depth + 1
|
||||
local node = minetest.get_node({x=tpos.x,y=tpos.y-y,z=tpos.z})
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
if not (def and def.walkable and def.liquidtype == "none" and def.is_ground_content) then
|
||||
bpos.y = tpos.y-y+1
|
||||
break
|
||||
if real_depth <= 6 then
|
||||
minetest.log("not deep enough")
|
||||
return false
|
||||
end
|
||||
local path = modpath.."/schematics/mcl_structures_igloo_basement.mts"
|
||||
mcl_structures.place_schematic(bpos, 0, nil, nil, path, rotation, nil, true, nil, nil, pr, function(p1, p2)
|
||||
-- Generate ladder to basement
|
||||
local ladder = {name="mcl_core:ladder", param2=minetest.dir_to_wallmounted(tdir)}
|
||||
minetest.set_node(tpos, {name="mcl_doors:trapdoor", param2=20+minetest.dir_to_facedir(dir)}) -- TODO: more reliable param2
|
||||
for y=1, real_depth do
|
||||
set_brick(vector.new(tpos.x-1, tpos.y-y, tpos.z ))
|
||||
set_brick(vector.new(tpos.x+1, tpos.y-y, tpos.z ))
|
||||
set_brick(vector.new(tpos.x , tpos.y-y, tpos.z-1))
|
||||
set_brick(vector.new(tpos.x , tpos.y-y, tpos.z+1))
|
||||
minetest.set_node(vector.new(tpos.x, tpos.y-y, tpos.z), ladder)
|
||||
end
|
||||
mcl_structures.fill_chests(p1,p2,def.loot,pr)
|
||||
mcl_structures.construct_nodes(p1,p2,{"mcl_brewing:stand_000","mcl_books:bookshelf"})
|
||||
spawn_mobs(p1,p2)
|
||||
end)
|
||||
end
|
||||
if real_depth <= 6 then
|
||||
return success
|
||||
end
|
||||
-- Generate ladder to basement
|
||||
for y=1, real_depth-1 do
|
||||
set_brick({x=tpos.x-1,y=tpos.y-y,z=tpos.z })
|
||||
set_brick({x=tpos.x+1,y=tpos.y-y,z=tpos.z })
|
||||
set_brick({x=tpos.x ,y=tpos.y-y,z=tpos.z-1})
|
||||
set_brick({x=tpos.x ,y=tpos.y-y,z=tpos.z+1})
|
||||
minetest.set_node({x=tpos.x,y=tpos.y-y,z=tpos.z}, {name="mcl_core:ladder", param2=ladder_param2})
|
||||
end
|
||||
-- Place basement
|
||||
mcl_structures.generate_igloo_basement(bpos, rotation, def.loot, pr)
|
||||
-- Place hidden trapdoor
|
||||
minetest.after(5, function(tpos, dir)
|
||||
minetest.set_node(tpos, {name="mcl_doors:trapdoor", param2=20+minetest.dir_to_facedir(dir)}) -- TODO: more reliable param2
|
||||
end, tpos, dir)
|
||||
end
|
||||
return success
|
||||
end)
|
||||
return true
|
||||
end
|
||||
|
||||
mcl_structures.register_structure("igloo",{
|
||||
place_on = {"mcl_core:snowblock","mcl_core:snow","group:grass_block_snow"},
|
||||
fill_ratio = 0.01,
|
||||
sidelen = 16,
|
||||
chunk_probability = 250,
|
||||
chunk_probability = 7,
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
y_max = mcl_vars.mg_overworld_max,
|
||||
y_min = 0,
|
||||
y_offset = 0,
|
||||
biomes = { "ColdTaiga", "IcePlainsSpikes", "IcePlains" },
|
||||
place_func = mcl_structures.generate_igloo,
|
||||
y_offset = -2,
|
||||
biomes = { "ColdTaiga", "IcePlainsSpikes", "IcePlains" },
|
||||
place_func = generate_igloo,
|
||||
loot = {
|
||||
["mcl_chests:chest_small"] = {{
|
||||
stacks_min = 1,
|
||||
|
|
|
@ -5,6 +5,7 @@ local modpath = minetest.get_modpath(modname)
|
|||
mcl_structures = {}
|
||||
|
||||
dofile(modpath.."/api.lua")
|
||||
dofile(modpath.."/foundation.lua")
|
||||
dofile(modpath.."/shipwrecks.lua")
|
||||
dofile(modpath.."/desert_temple.lua")
|
||||
dofile(modpath.."/jungle_temple.lua")
|
||||
|
@ -21,12 +22,11 @@ dofile(modpath.."/end_city.lua")
|
|||
|
||||
mcl_structures.register_structure("desert_well",{
|
||||
place_on = {"group:sand"},
|
||||
fill_ratio = 0.01,
|
||||
flags = "place_center_x, place_center_z",
|
||||
not_near = { "desert_temple_new" },
|
||||
solid_ground = true,
|
||||
sidelen = 4,
|
||||
chunk_probability = 600,
|
||||
chunk_probability = 15,
|
||||
y_max = mcl_vars.mg_overworld_max,
|
||||
y_min = 1,
|
||||
y_offset = -2,
|
||||
|
@ -36,11 +36,10 @@ mcl_structures.register_structure("desert_well",{
|
|||
|
||||
mcl_structures.register_structure("fossil",{
|
||||
place_on = {"group:material_stone","group:sand"},
|
||||
fill_ratio = 0.01,
|
||||
flags = "place_center_x, place_center_z",
|
||||
solid_ground = true,
|
||||
sidelen = 13,
|
||||
chunk_probability = 1000,
|
||||
chunk_probability = 25,
|
||||
y_offset = function(pr) return ( pr:next(1,16) * -1 ) -16 end,
|
||||
y_max = 15,
|
||||
y_min = mcl_vars.mg_overworld_min + 35,
|
||||
|
@ -102,7 +101,8 @@ minetest.register_chatcommand("spawnstruct", {
|
|||
pos = vector.round(pos)
|
||||
local dir = minetest.yaw_to_dir(player:get_look_horizontal())
|
||||
local rot = dir_to_rotation(dir)
|
||||
local pr = PseudoRandom(pos.x+pos.y+pos.z)
|
||||
local seed = minetest.hash_node_position(pos)
|
||||
local pr = PcgRandom(seed)
|
||||
local errord = false
|
||||
local message = S("Structure placed.")
|
||||
if param == "dungeon" and mcl_dungeons and mcl_dungeons.spawn_dungeon then
|
||||
|
@ -113,7 +113,7 @@ minetest.register_chatcommand("spawnstruct", {
|
|||
else
|
||||
for n,d in pairs(mcl_structures.registered_structures) do
|
||||
if n == param then
|
||||
mcl_structures.place_structure(pos,d,pr,math.random(),rot)
|
||||
mcl_structures.place_structure(pos,d,pr,seed,rot)
|
||||
return true,message
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,12 +4,10 @@ local modpath = minetest.get_modpath(modname)
|
|||
|
||||
mcl_structures.register_structure("jungle_temple",{
|
||||
place_on = {"group:grass_block","group:dirt","mcl_core:dirt_with_grass"},
|
||||
fill_ratio = 0.01,
|
||||
flags = "place_center_x, place_center_z",
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
y_offset = function(pr) return pr:next(-3,0) -5 end,
|
||||
chunk_probability = 200,
|
||||
chunk_probability = 5,
|
||||
y_max = mcl_vars.mg_overworld_max,
|
||||
y_min = 1,
|
||||
biomes = { "Jungle" },
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_structures
|
||||
author = Wuzzy, cora
|
||||
author = Wuzzy, cora, kno10
|
||||
description = Structure placement for MCL2
|
||||
depends = mcl_init, mcl_loot
|
||||
depends = mcl_init, mcl_util, mcl_loot
|
||||
|
|
|
@ -74,15 +74,13 @@ local cold = {
|
|||
place_on = {"group:sand","mcl_core:gravel","mcl_core:dirt","mcl_core:clay","group:material_stone"},
|
||||
spawn_by = {"mcl_core:water_source"},
|
||||
num_spawn_by = 2,
|
||||
fill_ratio = 0.01,
|
||||
flags = "place_center_x, place_center_z, force_placement",
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
y_offset = -1,
|
||||
y_min = mcl_vars.mg_overworld_min,
|
||||
y_max = -2,
|
||||
biomes = cold_oceans,
|
||||
chunk_probability = 400,
|
||||
chunk_probability = 10,
|
||||
sidelen = 20,
|
||||
filenames = {
|
||||
modpath.."/schematics/mcl_structures_ocean_ruins_cold_1.mts",
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local S = minetest.get_translator(modname)
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
local peaceful = minetest.settings:get_bool("only_peaceful_mobs", false)
|
||||
|
||||
local spawnon = {"mcl_core:stripped_oak","mcl_stairs:slab_birchwood_top"}
|
||||
|
||||
mcl_structures.register_structure("pillager_outpost",{
|
||||
place_on = {"group:grass_block","group:dirt","mcl_core:dirt_with_grass","group:sand"},
|
||||
fill_ratio = 0.01,
|
||||
flags = "place_center_x, place_center_z",
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
sidelen = 32,
|
||||
prepare = { padding = 2, corners = 4, foundation = 6, clearance = true },
|
||||
sidelen = 20,
|
||||
y_offset = 0,
|
||||
chunk_probability = 600,
|
||||
chunk_probability = 15,
|
||||
y_max = mcl_vars.mg_overworld_max,
|
||||
y_min = 1,
|
||||
biomes = { "Desert", "Plains", "Savanna", "IcePlains", "Taiga" },
|
||||
|
@ -63,17 +60,10 @@ mcl_structures.register_structure("pillager_outpost",{
|
|||
}}
|
||||
},
|
||||
after_place = function(p,def,pr)
|
||||
local p1 = vector.offset(p,-9,0,-9)
|
||||
local p2 = vector.offset(p,9,32,9)
|
||||
local p1, p2 = vector.offset(p,-9,0,-9), vector.offset(p,9,32,9)
|
||||
mcl_structures.spawn_mobs("mobs_mc:pillager",spawnon,p1,p2,pr,5)
|
||||
mcl_structures.spawn_mobs("mobs_mc:parrot",{"mesecons_pressureplates:pressure_plate_stone_off"},p1,p2,pr,3)
|
||||
mcl_structures.spawn_mobs("mobs_mc:iron_golem",{"mesecons_button:button_stone_off"},p1,p2,pr,1)
|
||||
for _,n in pairs(minetest.find_nodes_in_area(p1,p2,{"group:wall"})) do
|
||||
local def = minetest.registered_nodes[minetest.get_node(n).name:gsub("_%d+$","")]
|
||||
if def and def.on_construct then
|
||||
def.on_construct(n)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
|
|
|
@ -12,14 +12,13 @@ end
|
|||
|
||||
local def = {
|
||||
place_on = {"group:grass_block","group:dirt","mcl_core:dirt_with_grass","group:grass_block","group:sand","group:grass_block_snow","mcl_core:snow"},
|
||||
fill_ratio = 0.006,
|
||||
flags = "place_center_x, place_center_z, all_floors",
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
chunk_probability = 800,
|
||||
prepare = { padding = 0, corners = 3, tolerance = 10, foundation = true, clearance = true },
|
||||
chunk_probability = 20,
|
||||
y_max = mcl_vars.mg_overworld_max,
|
||||
y_min = 1,
|
||||
sidelen = 10,
|
||||
sidelen = 12,
|
||||
y_offset = -5,
|
||||
filenames = {
|
||||
modpath.."/schematics/mcl_structures_ruined_portal_1.mts",
|
||||
|
|
|
@ -41,10 +41,10 @@ end
|
|||
|
||||
mcl_structures.register_structure("witch_hut",{
|
||||
place_on = {"mcl_core:water_source","mclx_core:river_water_source"},
|
||||
fill_ratio = 0.01,
|
||||
flags = "place_center_x, place_center_z, liquid_surface, force_placement",
|
||||
sidelen = 8,
|
||||
chunk_probability = 300,
|
||||
chunk_probability = 8,
|
||||
prepare = { tolerance=-1, clearance="top", foundation=false },
|
||||
y_max = mcl_vars.mg_overworld_max,
|
||||
y_min = -4,
|
||||
y_offset = 0,
|
||||
|
|
|
@ -7,11 +7,11 @@ local spawnon = {"mcl_deepslate:deepslate","mcl_core:birchwood","mcl_wool:red_ca
|
|||
|
||||
mcl_structures.register_structure("woodland_cabin",{
|
||||
place_on = {"group:grass_block","group:dirt","mcl_core:dirt_with_grass"},
|
||||
fill_ratio = 0.01,
|
||||
flags = "place_center_x, place_center_z",
|
||||
solid_ground = true,
|
||||
make_foundation = true,
|
||||
chunk_probability = 800,
|
||||
prepare = { padding = 2, corners = 5, foundation = true, clearance = true },
|
||||
force_placement = false,
|
||||
chunk_probability = 20,
|
||||
y_max = mcl_vars.mg_overworld_max,
|
||||
y_min = 1,
|
||||
biomes = { "RoofedForest" },
|
||||
|
|
|
@ -2,11 +2,13 @@ local min_jobs = tonumber(minetest.settings:get("mcl_villages_min_jobs")) or 1
|
|||
local max_jobs = tonumber(minetest.settings:get("mcl_villages_max_jobs")) or 12
|
||||
local placement_priority = minetest.settings:get("mcl_villages_placement_priority") or "random"
|
||||
|
||||
local foundation_materials = {}
|
||||
foundation_materials["mcl_core:sand"] = "mcl_core:sandstone"
|
||||
foundation_materials["mcl_core:redsand"] = "mcl_core:redsandstone"
|
||||
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize settlement_info
|
||||
-------------------------------------------------------------------------------
|
||||
function mcl_villages.initialize_settlement_info(pr)
|
||||
local count_buildings = {
|
||||
number_of_jobs = pr:next(min_jobs, max_jobs),
|
||||
|
@ -51,21 +53,18 @@ local function spawn_cats(pos)
|
|||
end
|
||||
|
||||
local function init_nodes(p1, p2, pr)
|
||||
--[[for _, n in pairs(minetest.find_nodes_in_area(p1, p2, { "group:wall" })) do
|
||||
mcl_walls.update_wall(n)
|
||||
end]]--
|
||||
|
||||
construct_node(p1, p2, "mcl_itemframes:item_frame")
|
||||
construct_node(p1, p2, "mcl_itemframes:glow_item_frame")
|
||||
construct_node(p1, p2, "mcl_furnaces:furnace")
|
||||
construct_node(p1, p2, "mcl_anvils:anvil")
|
||||
|
||||
construct_node(p1, p2, "mcl_books:bookshelf")
|
||||
construct_node(p1, p2, "mcl_armor_stand:armor_stand")
|
||||
--construct_node(p1, p2, "mcl_smoker:smoker")
|
||||
--construct_node(p1, p2, "mcl_barrels:barrel_closed")
|
||||
--construct_node(p1, p2, "mcl_blast_furnace:blast_furnace")
|
||||
--construct_node(p1, p2, "mcl_brewing:stand_000")
|
||||
mcl_structures.construct_nodes(p1, p2, {
|
||||
"mcl_itemframes:item_frame",
|
||||
"mcl_itemframes:glow_item_frame",
|
||||
"mcl_furnaces:furnace",
|
||||
"mcl_anvils:anvil",
|
||||
"mcl_books:bookshelf",
|
||||
"mcl_armor_stand:armor_stand",
|
||||
-- "mcl_smoker:smoker",
|
||||
-- "mcl_barrels:barrel_closed",
|
||||
-- "mcl_blast_furnace:blast_furnace",
|
||||
-- "mcl_brewing:stand_000",
|
||||
})
|
||||
|
||||
-- Support mods with custom job sites
|
||||
local job_sites = minetest.find_nodes_in_area(p1, p2, mobs_mc.jobsites)
|
||||
|
@ -94,7 +93,7 @@ end
|
|||
local function check_ground(lvm, cpos, size)
|
||||
local cpos, surface_material = mcl_villages.find_surface(lvm, cpos)
|
||||
if not cpos then return nil, nil end
|
||||
local pos = vector.offset(cpos, -math.floor(size.x/2), 0, -math.floor(size.z/2))
|
||||
local pos = vector.offset(cpos, -math.floor((size.x-1)/2), 0, -math.floor((size.z-1)/2))
|
||||
local ys = {pos.y}
|
||||
local pos_c = mcl_villages.find_surface_down(lvm, vector.offset(pos, 0, size.y, 0))
|
||||
if pos_c then table.insert(ys, pos_c.y) end
|
||||
|
@ -139,10 +138,10 @@ local function layout_town(lvm, minp, maxp, pr, input_settlement)
|
|||
local building = table.copy(input_settlement[#settlement + 1])
|
||||
local size = vector.copy(building.size)
|
||||
--local rotation = possible_rotations[pr:next(1, #possible_rotations)]
|
||||
local rotation = math.floor(math.atan2(center.x-cpos.x, center.z-cpos.z) / math.pi * 2+4.5)%4
|
||||
local rotation = possible_rotations[1+rotation]
|
||||
local rotation = math.floor(math.atan2(center.z-cpos.z, center.x-cpos.x) / math.pi * 2+6.5)%4
|
||||
rotation = possible_rotations[1+rotation]
|
||||
if rotation == "90" or rotation == "270" then size.x, size.z = size.z, size.x end
|
||||
local tlpos = vector.offset(cpos, -math.floor(size.x / 2), 0, -math.floor(size.z / 2))
|
||||
local tlpos = vector.offset(cpos, -math.floor((size.x-1)/2), 0, -math.floor((size.z-1)/2))
|
||||
|
||||
-- ensure we have 3 space for terraforming, and avoid problems with VoxelManip
|
||||
if tlpos.x - 3 >= minp.x and tlpos.x + size.x + 3 <= maxp.x
|
||||
|
@ -155,8 +154,8 @@ local function layout_town(lvm, minp, maxp, pr, input_settlement)
|
|||
center_surface, y = cpos, math.min(maxp.y, pos.y + mcl_villages.max_height_difference * 0.5 + 1)
|
||||
end
|
||||
-- limit height differences to town center, but gradually allow more
|
||||
if math.abs(pos.y - center_surface.y) <= mcl_villages.max_height_difference * (0.25 + math.min(r/30,0.5)) then
|
||||
local minp = vector.offset(pos, -math.floor(size.x/2), building.yadjust, -math.floor(size.z/2))
|
||||
if math.abs(pos.y - center_surface.y) <= mcl_villages.max_height_difference * (0.25 + math.min(r/40,0.5)) then
|
||||
local minp = vector.offset(pos, -math.floor((size.x-1)/2), building.yadjust, -math.floor((size.z-1)/2))
|
||||
building.minp = minp
|
||||
building.maxp = vector.offset(minp, size.x, size.y, size.z)
|
||||
building.pos = pos
|
||||
|
@ -279,8 +278,8 @@ function mcl_villages.place_schematics(lvm, settlement, blockseed, pr)
|
|||
local surface_material = building.surface_mat or {name = "mcl_core:dirt" }
|
||||
local platform_material = building.platform_mat or building.surface_mat or {name = "mcl_core:stone" }
|
||||
local schem_lua = building.schem_lua
|
||||
schem_lua = schem_lua:gsub('"mcl_core:dirt"', '"'..platform_material.name..'"') -- also keeping param2 would be nicer, grass color
|
||||
schem_lua = schem_lua:gsub('"mcl_core:dirt_with_grass"', '"'..surface_material.name..'"')
|
||||
schem_lua = schem_lua:gsub('"mcl_core:dirt"', '"'..platform_material.name..'"')
|
||||
schem_lua = schem_lua:gsub('"mcl_core:dirt_with_grass"', '"'..surface_material.name..'"') -- also keeping param2 would be nicer, grass color
|
||||
schem_lua = mcl_villages.substitute_materials(cpos, schem_lua, pr)
|
||||
local schematic = loadstring(schem_lua)()
|
||||
|
||||
|
@ -439,3 +438,28 @@ function mcl_villages.post_process_village(blockseed)
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Terraform for an entire village
|
||||
function mcl_villages.terraform(lvm, settlement, pr)
|
||||
-- TODO: further optimize by using raw data arrays instead of set_node_at. But OK for a first draft.
|
||||
-- we make the foundations 1 node wider than requested, to have one node for path laying
|
||||
for i, building in ipairs(settlement) do
|
||||
if not building.no_clearance then
|
||||
local pos, size = building.pos, building.size
|
||||
pos = vector.offset(pos, -math.floor(size.x/2), 0, -math.floor(size.z/2))
|
||||
mcl_structures.clearance(lvm, pos.x-1, pos.y, pos.z-1, size.x+2, size.y, size.z+2, 2, building.surface_mat, pr)
|
||||
end
|
||||
end
|
||||
for i, building in ipairs(settlement) do
|
||||
if not building.no_ground_turnip then
|
||||
local pos, size = building.pos, building.size
|
||||
local surface_mat = building.surface_mat
|
||||
local platform_mat = building.platform_mat or { name = foundation_materials[surface_mat.name] or "mcl_core:dirt" }
|
||||
local stone_mat = building.stone_mat or { name = "mcl_core:stone" }
|
||||
building.platform_mat = platform_mat -- remember for use in schematic placement
|
||||
building.stone_mat = stone_mat
|
||||
pos = vector.offset(pos, -math.floor((size.x-1)/2), 0, -math.floor((size.z-1)/2))
|
||||
mcl_structures.foundation(lvm, pos.x-2, pos.y, pos.z-2, size.x+4, -4, size.z+4, 2, surface_mat, platform_mat, stone_mat, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
local foundation_materials = {}
|
||||
foundation_materials["mcl_core:sand"] = "mcl_core:sandstone"
|
||||
foundation_materials["mcl_core:redsand"] = "mcl_core:redsandstone"
|
||||
|
||||
local function is_air(node)
|
||||
return not node or node.name == "air" or node.name == "ignore" or node.name == "mcl_villages:no_paths"
|
||||
end
|
||||
local function is_solid(node)
|
||||
if not node or node.name == "air" or node.name == "ignore" or node.name == "mcl_villages:no_paths" then return false end
|
||||
--if string.find(node.name,"leaf") then return false end
|
||||
--if string.find(node.name,"tree") then return false end
|
||||
local ndef = minetest.registered_nodes[node.name]
|
||||
return ndef and ndef.walkable
|
||||
end
|
||||
local function make_solid(lvm, cp, with, except)
|
||||
local cur = lvm:get_node_at(cp)
|
||||
if not is_solid(cur) or (except and cur.name == except.name) then
|
||||
lvm:set_node_at(cp, with)
|
||||
end
|
||||
end
|
||||
local function excavate(lvm,xi,yi,zi,pr)
|
||||
local pos, n, c = vector.new(xi,yi,zi), nil, 0
|
||||
local node = lvm:get_node_at(pos)
|
||||
if is_air(node) then return false end -- already empty, nothing to do
|
||||
pos.y = pos.y-1
|
||||
if not is_air(lvm:get_node_at(pos)) then return false end -- below is solid, do not clear above anymore
|
||||
-- count empty nodes below otherwise
|
||||
for x = xi-1,xi+1 do
|
||||
for z = zi-1,zi+1 do
|
||||
pos.x, pos.z = x, z
|
||||
if is_air(lvm:get_node_at(pos)) then c = c + 1 end
|
||||
end
|
||||
end
|
||||
-- try to completely remove trees overhead
|
||||
if not string.find(node.name, "leaf") and not string.find(node.name, "tree") then
|
||||
-- stop randomly depending on fill, to narrow down the caves
|
||||
if (pr:next(0,1e9)/1e9)^2 > c/9.1 then return false end
|
||||
end
|
||||
lvm:set_node_at(vector.new(xi, yi, zi),{name="air"})
|
||||
return true -- modified
|
||||
end
|
||||
local function grow_foundation(lvm,xi,yi,zi,pr,surface_mat,platform_mat)
|
||||
local pos, n, c = vector.new(xi,yi,zi), nil, 0
|
||||
if is_solid(lvm:get_node_at(pos)) then return false end -- already solid, nothing to do
|
||||
pos.y = pos.y+1
|
||||
local cur = lvm:get_node_at(pos)
|
||||
if not is_solid(cur) then return false end -- above is empty, do not fill below
|
||||
if cur and cur.name and cur.name ~= surface_mat.name then platform_mat = cur end
|
||||
if pr:next(1,5) == 5 then -- randomly switch to stone sometimes
|
||||
platform_mat = { name = "mcl_core:stone" }
|
||||
end
|
||||
-- count solid nodes above otherwise
|
||||
for x = xi-1,xi+1 do
|
||||
for z = zi-1,zi+1 do
|
||||
pos.x, pos.z = x, z
|
||||
if is_solid(lvm:get_node_at(pos)) then c = c + 1 end
|
||||
end
|
||||
end
|
||||
-- stop randomly depending on fill, to narrow down the foundation
|
||||
if (pr:next(0,1e9)/1e9)^2 > c/9.1 then return false end
|
||||
lvm:set_node_at(vector.new(xi, yi, zi), platform_mat)
|
||||
return true -- modified
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function clear space above baseplate
|
||||
-------------------------------------------------------------------------------
|
||||
function mcl_villages.terraform(lvm, settlement, pr)
|
||||
-- TODO: further optimize by using raw data arrays instead of set_node_at. But OK for a first draft.
|
||||
--local lvm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
--local lvm = VoxelManip()
|
||||
|
||||
-- we make the foundations 1 node wider than requested, to have one node for path laying
|
||||
for i, building in ipairs(settlement) do
|
||||
--lvm:read_from_map(vector.new(pos.x-2, pos.y-20, pos.z-2), vector.new(pos.x+sx+2, pos.y+sy+20, pos.z+sz+2))
|
||||
--lvm:get_data()
|
||||
if not building.no_clearance then
|
||||
local pos, size = building.pos, building.size
|
||||
pos = vector.offset(pos, -math.floor(size.x/2)-1, 0, -math.floor(size.z/2)-1)
|
||||
mcl_villages.clearance(lvm, pos.x, pos.y, pos.z, size.x+2, size.y, size.z+2, pr)
|
||||
end
|
||||
--lvm:write_to_map(false)
|
||||
end
|
||||
for i, building in ipairs(settlement) do
|
||||
if not building.no_ground_turnip then
|
||||
local pos, size = building.pos, building.size
|
||||
local surface_mat = building.surface_mat
|
||||
local platform_mat = building.platform_mat or { name = foundation_materials[surface_mat.name] or "mcl_core:dirt" }
|
||||
building.platform_mat = platform_mat -- remember for use in schematic placement
|
||||
pos = vector.offset(pos, -math.floor(size.x/2)-1, 0, -math.floor(size.z/2)-1)
|
||||
mcl_villages.foundation(lvm, pos.x, pos.y, pos.z, size.x+2, -4, size.z+2, surface_mat, platform_mat, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
local AIR = {name = "air"}
|
||||
function mcl_villages.clearance(lvm, px, py, pz, sx, sy, sz, pr)
|
||||
-- excavate the needed volume, some headroom, and add a baseplate
|
||||
for xi = px,px+sx-1 do
|
||||
for zi = pz,pz+sz-1 do
|
||||
lvm:set_node_at(vector.new(xi, py+1, zi),AIR)
|
||||
-- py+2 to py+5 are filled larger below!
|
||||
for yi = py+6,py+sy do
|
||||
lvm:set_node_at(vector.new(xi, yi, zi),AIR)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- slightly widen the cave, to make easier to enter for mobs
|
||||
for xi = px-1,px+sx do
|
||||
for zi = pz-1,pz+sz do
|
||||
for yi = py+2,py+5 do
|
||||
lvm:set_node_at(vector.new(xi, yi, zi),AIR)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- some extra gaps
|
||||
for xi = px-2,px+sx+1 do
|
||||
for zi = pz-2,pz+sz+1 do
|
||||
if pr:next(1,4) == 1 then
|
||||
for yi = py+3,py+5 do
|
||||
lvm:set_node_at(vector.new(xi, yi, zi),AIR)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- cave some additional area overhead, try to make it interesting though
|
||||
for yi = py+3,py+sy*3 do
|
||||
local active = false
|
||||
for xi = px-2,px+sx+1 do
|
||||
for zi = pz-2,pz+sz+1 do
|
||||
if excavate(lvm,xi,yi,zi,pr) then active = true end
|
||||
end
|
||||
end
|
||||
if not active and yi > py+sy+5 then break end
|
||||
end
|
||||
end
|
||||
function mcl_villages.foundation(lvm, px, py, pz, sx, sy, sz, surface_mat, platform_mat, pr)
|
||||
-- generate a baseplate
|
||||
for xi = px,px+sx-1 do
|
||||
for zi = pz,pz+sz-1 do
|
||||
lvm:set_node_at(vector.new(xi, py, zi), surface_mat)
|
||||
make_solid(lvm, vector.new(xi, py - 1, zi), platform_mat)
|
||||
end
|
||||
end
|
||||
-- slightly widen the baseplate, to make easier to enter for mobs
|
||||
for xi = px,px+sx-1 do
|
||||
make_solid(lvm, vector.new(xi, py-1, pz-1), surface_mat, platform_mat)
|
||||
make_solid(lvm, vector.new(xi, py-1, pz), platform_mat)
|
||||
make_solid(lvm, vector.new(xi, py-1, pz+sz-1), platform_mat)
|
||||
make_solid(lvm, vector.new(xi, py-1, pz+sz), surface_mat, platform_mat)
|
||||
end
|
||||
for zi = pz,pz+sz-1 do
|
||||
make_solid(lvm, vector.new(px-1, py-1, zi), surface_mat, platform_mat)
|
||||
make_solid(lvm, vector.new(px, py-1, zi), platform_mat)
|
||||
make_solid(lvm, vector.new(px+sx-1, py-1, zi), platform_mat)
|
||||
make_solid(lvm, vector.new(px+sx, py-1, zi), surface_mat, platform_mat)
|
||||
end
|
||||
-- make some additional steps, along both x sides
|
||||
for xi = px,px+sx-1 do
|
||||
local cp = vector.new(xi, py-3, pz-1)
|
||||
if is_solid(lvm:get_node_at(cp)) then
|
||||
cp = vector.new(xi, py-2, pz-1)
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
cp.z = pz-2
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
end
|
||||
local cp = vector.new(xi, py-3, pz+sz)
|
||||
if is_solid(lvm:get_node_at(cp)) then
|
||||
cp = vector.new(xi, py-2, pz+sz)
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
cp.z = pz + sz + 1
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
end
|
||||
end
|
||||
-- make some additional steps, along both z sides
|
||||
for zi = pz,pz+sz-1 do
|
||||
local cp = vector.new(px-1, py-3, zi)
|
||||
if is_solid(lvm:get_node_at(cp)) then
|
||||
cp = vector.new(px-1, py-2, zi)
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
cp.x = px-2
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
end
|
||||
local cp = vector.new(px+sx, py-3, zi)
|
||||
if is_solid(lvm:get_node_at(cp)) then
|
||||
cp = vector.new(px+sx, py-2, zi)
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
cp.x = px+sx+1
|
||||
make_solid(lvm, cp, surface_mat, platform_mat)
|
||||
end
|
||||
end
|
||||
-- construct additional baseplate below, also try to make it interesting
|
||||
for yi = py-2,py-20,-1 do
|
||||
local active = false
|
||||
for xi = px-1,px+sx do
|
||||
for zi = pz-1,pz+sz do
|
||||
if grow_foundation(lvm,xi,yi,zi,pr,surface_mat,platform_mat) then active = true end
|
||||
end
|
||||
end
|
||||
if not active and yi < py + sy then break end
|
||||
end
|
||||
end
|
|
@ -5,7 +5,6 @@ local village_chance = tonumber(minetest.settings:get("mcl_villages_village_prob
|
|||
|
||||
dofile(mcl_villages.modpath.."/const.lua")
|
||||
dofile(mcl_villages.modpath.."/utils.lua")
|
||||
dofile(mcl_villages.modpath.."/foundation.lua")
|
||||
dofile(mcl_villages.modpath.."/buildings.lua")
|
||||
dofile(mcl_villages.modpath.."/paths.lua")
|
||||
dofile(mcl_villages.modpath.."/api.lua")
|
||||
|
@ -13,12 +12,9 @@ dofile(mcl_villages.modpath.."/api.lua")
|
|||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
minetest.register_alias("mcl_villages:stonebrickcarved", "mcl_core:stonebrickcarved")
|
||||
-- In 2025, remove structblock: minetest.register_alias("mcl_villages:structblock", "air")
|
||||
minetest.register_node("mcl_villages:structblock", {drawtype="airlike",groups = {not_in_creative_inventory=1},})
|
||||
-- we currently do not support/use these from MCLA:
|
||||
--minetest.register_alias("mcl_villages:village_block", "air")
|
||||
--minetest.register_alias("mcl_villages:no_paths", "air")
|
||||
--minetest.register_alias("mcl_villages:path_endpoint", "air")
|
||||
--minetest.register_alias("mcl_villages:building_block", "air")
|
||||
--
|
||||
-- on map generation, try to build a settlement
|
||||
|
@ -26,15 +22,15 @@ minetest.register_node("mcl_villages:structblock", {drawtype="airlike",groups =
|
|||
local function build_a_settlement(minp, maxp, blockseed)
|
||||
if mcl_villages.village_exists(blockseed) then return end
|
||||
local pr = PcgRandom(blockseed)
|
||||
local lvm = VoxelManip()
|
||||
lvm:read_from_map(minp, maxp)
|
||||
local lvm = VoxelManip(minp, maxp)
|
||||
local settlement = mcl_villages.create_site_plan(lvm, minp, maxp, pr)
|
||||
if not settlement then return false, false end
|
||||
-- all foundations first, then all buildings, to avoid damaging very close buildings
|
||||
mcl_villages.terraform(lvm, settlement, pr)
|
||||
mcl_villages.place_schematics(lvm, settlement, blockseed, pr)
|
||||
mcl_villages.add_village(blockseed, settlement)
|
||||
--lvm:write_to_map(false)
|
||||
--lvm:write_to_map(true) -- destory paths as of now
|
||||
--mcl_villages.paths(blockseed) -- TODO: biome
|
||||
for _, on_village_placed_callback in pairs(mcl_villages.on_village_placed) do
|
||||
on_village_placed_callback(settlement, blockseed)
|
||||
end
|
||||
|
@ -49,6 +45,17 @@ end
|
|||
-- Disable natural generation in singlenode.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if mg_name ~= "singlenode" then
|
||||
mcl_mapgen_core.register_generator("villages", nil, function(minp, maxp, blockseed)
|
||||
if maxp.y < 0 then return end
|
||||
if village_chance == 0 then return end
|
||||
local pr = PcgRandom(blockseed)
|
||||
if pr:next(0, 100) > village_chance then return end
|
||||
local big_minp = vector.copy(minp) --vector.offset(minp, -16, -16, -16)
|
||||
local big_maxp = vector.copy(maxp) --vector.offset(maxp, 16, 16, 16)
|
||||
minetest.emerge_area(big_minp, big_maxp, ecb_village,
|
||||
{ minp = vector.copy(minp), maxp = vector.copy(maxp), blockseed = blockseed }
|
||||
)
|
||||
end)
|
||||
--[[ did not work, because later structure generation would make holes in our schematics
|
||||
mcl_mapgen_core.register_generator("villages", function(lvm, data, data2, e1, e2, area, minp, maxp, blockseed)
|
||||
if mcl_villages.village_exists(blockseed) then return false, false end
|
||||
|
@ -74,6 +81,7 @@ if mg_name ~= "singlenode" then
|
|||
end
|
||||
end, 15000)
|
||||
]]--
|
||||
--[[ causes issues when vertically close to the chunk boundary:
|
||||
mcl_mapgen_core.register_generator("villages", nil, function(minp, maxp, blockseed)
|
||||
if maxp.y < 0 or mcl_villages.village_exists(blockseed) then return end
|
||||
local pr = PcgRandom(blockseed)
|
||||
|
@ -90,6 +98,7 @@ if mg_name ~= "singlenode" then
|
|||
--lvm:write_to_map(true)
|
||||
--mcl_villages.paths(blockseed) -- TODO: biome
|
||||
end, 15000)
|
||||
]]--
|
||||
end
|
||||
|
||||
-- This is a light source so that lamps don't get placed near it
|
||||
|
@ -111,17 +120,16 @@ minetest.register_node("mcl_villages:village_block", {
|
|||
end,
|
||||
})
|
||||
|
||||
-- LEGACY, for spawning "planned" cities in old maps. Remove in 2025?
|
||||
-- struct to cause a village spawn when it can be fully emerged
|
||||
minetest.register_lbm({
|
||||
name = "mcl_villages:structblock",
|
||||
run_at_every_load = true,
|
||||
nodenames = {"mcl_villages:structblock"},
|
||||
action = function(pos, node)
|
||||
minetest.set_node(pos, {name = "air"})
|
||||
local px, py, pz = math.floor(pos.x / 16) * 16, math.floor(pos.y / 16) * 16, math.floor(pos.z / 16) * 16
|
||||
local minp=vector.new(px, py, pz)
|
||||
local maxp=vector.new(px + 80, py + 80, pz + 80)
|
||||
local blockseed = PcgRandom(px * 223 + py * 17 + pz):next()
|
||||
local minp=vector.offset(pos, -40, -40, -40)
|
||||
local maxp=vector.offset(pos, 40, 40, 40)
|
||||
local blockseed = PcgRandom(minetest.hash_node_position(pos)):next()
|
||||
minetest.emerge_area(minp, maxp, ecb_village, {minp=minp, maxp=maxp, blockseed=blockseed})
|
||||
end
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name = mcl_villages
|
||||
author = Rochambeau
|
||||
author = Rochambeau, kno10
|
||||
description = This mod adds settlements on world generation.
|
||||
depends = mcl_util, mcl_mapgen_core, mcl_structures, mcl_core, mcl_loot, mobs_mc
|
||||
depends = mcl_core, mcl_util, mcl_mapgen_core, mcl_structures, mcl_loot, mobs_mc
|
||||
optional_depends = mcl_farming
|
||||
|
|
|
@ -66,18 +66,17 @@ local function smooth_path(path)
|
|||
local next_y = path[i + 1].y
|
||||
local bump_node = minetest.get_node(path[i])
|
||||
|
||||
-- TODO: replace bamboo underneath with dirt here?
|
||||
if minetest.get_item_group(bump_node.name, "water") ~= 0 then
|
||||
-- ignore in this pass
|
||||
elseif y >= next_y + 2 and y <= prev_y then
|
||||
local under_pos = vector.offset(path[i], 0, -1, 0)
|
||||
minetest.swap_node(under_pos, { name = "air" })
|
||||
minetest.swap_node(vector.offset(path[i], 0, -1, 0), { name = "air" })
|
||||
path[i].y = path[i].y - 1
|
||||
elseif y <= next_y - 2 and y >= prev_y then
|
||||
minetest.swap_node(path[i], { name = "mcl_core:dirt" })
|
||||
path[i].y = path[i].y + 1
|
||||
elseif y >= prev_y + 2 and y <= next_y then
|
||||
local under_pos = vector.offset(path[i], 0, -1, 0)
|
||||
minetest.swap_node(under_pos, { name = "air" })
|
||||
minetest.swap_node(vector.offset(path[i], 0, -1, 0), { name = "air" })
|
||||
path[i].y = path[i].y - 1
|
||||
elseif y <= prev_y - 2 and y >= prev_y then
|
||||
minetest.swap_node(path[i], { name = "mcl_core:dirt" })
|
||||
|
@ -88,8 +87,7 @@ local function smooth_path(path)
|
|||
path[i].y = path[i].y + 1
|
||||
elseif y > prev_y and y > next_y then
|
||||
-- Remove peak to flatten path
|
||||
local under_pos = vector.offset(path[i], 0, -1, 0)
|
||||
minetest.swap_node(under_pos, { name = "air" })
|
||||
minetest.swap_node(vector.offset(path[i], 0, -1, 0), { name = "air" })
|
||||
path[i].y = path[i].y - 1
|
||||
end
|
||||
end
|
||||
|
@ -125,9 +123,8 @@ local function place_path(path, pr, stair, slab)
|
|||
elseif y > prev_y and y > next_y then
|
||||
-- TODO: do not break other path/stairs
|
||||
-- Remove peak to flatten path
|
||||
local under_pos = vector.offset(path[i], 0, -1, 0)
|
||||
minetest.swap_node(under_pos, { name = "air" })
|
||||
path[i] = under_pos
|
||||
minetest.swap_node(vector.offset(path[i], 0, -1, 0), { name = "air" })
|
||||
path[i].y = path[i].y - 1
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
local function is_above_surface(name)
|
||||
-- TODO: use groups
|
||||
return name == "air" or
|
||||
-- note: not dirt_with_grass!
|
||||
string.find(name,"tree") or
|
||||
string.find(name,"leaves") or
|
||||
string.find(name,"snow") or
|
||||
string.find(name,"fern") or
|
||||
string.find(name,"flower") or -- includes grass decorations
|
||||
string.find(name,"bush") or
|
||||
name == "mcl_bamboo:bamboo" or name == "mcl_core:vine"
|
||||
if name == "air" or name == "mcl_bamboo:bamboo" or name == "mcl_core:vine" or name == "mcl_core:snow" then
|
||||
return true
|
||||
end
|
||||
local meta = core.registered_items[name]
|
||||
local groups = meta and meta.groups
|
||||
return groups and (groups["deco_block"] or groups["tree"] or groups["leaves"] or groups["plant"])
|
||||
end
|
||||
function mcl_villages.find_surface_down(lvm, pos, surface_node)
|
||||
local p6 = vector.new(pos)
|
||||
surface_node = surface_node or lvm:get_node_at(p6)
|
||||
if not surface_node then return end
|
||||
local has_air = is_above_surface(surface_node.name)
|
||||
for y = p6.y - 1, math.max(0,p6.y - 80), -1 do
|
||||
for y = p6.y - 1, math.max(0, p6.y - 80), -1 do
|
||||
p6.y = y
|
||||
local top_node = surface_node
|
||||
surface_node = lvm:get_node_at(p6)
|
||||
|
@ -97,7 +93,6 @@ function mcl_villages.fill_chest(pos, pr)
|
|||
if meta:get_string("infotext") ~= "Chest" then
|
||||
-- For MineClone2 0.70 or before
|
||||
minetest.registered_nodes["mcl_chests:chest"].on_construct(pos)
|
||||
--
|
||||
-- For MineClone2 after commit 09ab1482b5 (the new entity chests)
|
||||
minetest.registered_nodes["mcl_chests:chest_small"].on_construct(pos)
|
||||
end
|
||||
|
|
|
@ -1098,7 +1098,7 @@ end
|
|||
|
||||
mcl_structures.register_structure("mineshaft",{
|
||||
place_on = {"group:sand","group:grass_block","mcl_core:water_source","group:dirt","mcl_core:dirt_with_grass","mcl_core:gravel","group:material_stone","mcl_core:snow"},
|
||||
fill_ratio = 0.0001,
|
||||
chunk_probability = 4,
|
||||
flags = "place_center_x, place_center_z, force_placement, all_floors",
|
||||
sidelen = 32,
|
||||
y_max = 40,
|
||||
|
|
Loading…
Reference in New Issue