2021-01-27 09:56:53 +01:00
|
|
|
--[[
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- build schematic, replace material, rotation
|
|
|
|
-------------------------------------------------------------------------------
|
2024-07-19 14:56:06 +02:00
|
|
|
function mcl_villages.build_schematic(vm, data, va, pos, building, replace_wall, name)
|
2021-01-27 09:56:53 +01:00
|
|
|
-- get building node material for better integration to surrounding
|
2021-03-28 20:56:51 +02:00
|
|
|
local platform_material = mcl_vars.get_node(pos)
|
2021-02-22 00:15:32 +01:00
|
|
|
if not platform_material or (platform_material.name == "air" or platform_material.name == "ignore") then
|
2021-01-27 09:56:53 +01:00
|
|
|
return
|
|
|
|
end
|
|
|
|
platform_material = platform_material.name
|
|
|
|
-- pick random material
|
|
|
|
local material = wallmaterial[math.random(1,#wallmaterial)]
|
|
|
|
-- schematic conversion to lua
|
2021-04-17 07:42:49 +02:00
|
|
|
local schem_lua = minetest.serialize_schematic(building,
|
|
|
|
"lua",
|
2021-05-25 10:56:06 +02:00
|
|
|
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return schematic"
|
2021-01-27 09:56:53 +01:00
|
|
|
-- replace material
|
|
|
|
if replace_wall == "y" then
|
|
|
|
schem_lua = schem_lua:gsub("mcl_core:cobble", material)
|
|
|
|
end
|
2021-04-17 07:42:49 +02:00
|
|
|
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass",
|
2021-01-27 09:56:53 +01:00
|
|
|
platform_material)
|
|
|
|
|
|
|
|
-- Disable special junglewood for now.
|
|
|
|
-- special material for spawning npcs
|
2021-04-17 07:42:49 +02:00
|
|
|
-- schem_lua = schem_lua:gsub("mcl_core:junglewood",
|
2021-01-27 09:56:53 +01:00
|
|
|
-- "settlements:junglewood")
|
|
|
|
--
|
|
|
|
|
|
|
|
-- format schematic string
|
|
|
|
local schematic = loadstring(schem_lua)()
|
|
|
|
-- build foundation for the building an make room above
|
|
|
|
local width = schematic["size"]["x"]
|
|
|
|
local depth = schematic["size"]["z"]
|
|
|
|
local height = schematic["size"]["y"]
|
|
|
|
local possible_rotations = {"0", "90", "180", "270"}
|
|
|
|
local rotation = possible_rotations[ math.random( #possible_rotations ) ]
|
2024-07-19 14:56:06 +02:00
|
|
|
mcl_villages.foundation(
|
2021-04-17 07:42:49 +02:00
|
|
|
pos,
|
|
|
|
width,
|
|
|
|
depth,
|
|
|
|
height,
|
2021-01-27 09:56:53 +01:00
|
|
|
rotation)
|
|
|
|
vm:set_data(data)
|
|
|
|
-- place schematic
|
|
|
|
|
|
|
|
minetest.place_schematic_on_vmanip(
|
2021-04-17 07:42:49 +02:00
|
|
|
vm,
|
|
|
|
pos,
|
|
|
|
schematic,
|
|
|
|
rotation,
|
|
|
|
nil,
|
2021-01-27 09:56:53 +01:00
|
|
|
true)
|
|
|
|
vm:write_to_map(true)
|
|
|
|
end]]
|
|
|
|
-------------------------------------------------------------------------------
|
2021-04-17 07:42:49 +02:00
|
|
|
-- initialize settlement_info
|
2021-01-27 09:56:53 +01:00
|
|
|
-------------------------------------------------------------------------------
|
2024-07-19 14:56:06 +02:00
|
|
|
function mcl_villages.initialize_settlement_info(pr)
|
2021-01-27 09:56:53 +01:00
|
|
|
local count_buildings = {}
|
|
|
|
|
|
|
|
-- count_buildings table reset
|
2024-07-19 14:56:06 +02:00
|
|
|
for k,v in pairs(mcl_villages.schematic_table) do
|
2021-01-27 09:56:53 +01:00
|
|
|
count_buildings[v["name"]] = 0
|
|
|
|
end
|
|
|
|
|
|
|
|
-- randomize number of buildings
|
|
|
|
local number_of_buildings = pr:next(10, 25)
|
2024-07-19 14:56:06 +02:00
|
|
|
local number_built = 0
|
|
|
|
mcl_villages.debug("Village ".. number_of_buildings)
|
2021-01-27 09:56:53 +01:00
|
|
|
|
|
|
|
return count_buildings, number_of_buildings, number_built
|
|
|
|
end
|
2024-07-19 14:56:06 +02:00
|
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- check ground for a single building
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
local function try_place_building(pos_surface, building_all_info, rotation, settlement_info, pr)
|
|
|
|
local fwidth, fdepth = building_all_info["hwidth"], building_all_info["hdepth"]
|
|
|
|
if rotation == "90" or rotation == "270" then fwidth, fdepth = fdepth, fwidth end
|
|
|
|
local fheight = building_all_info["hheight"]
|
|
|
|
-- use building centers for better placement
|
|
|
|
pos_surface.x = pos_surface.x - math.ceil(fwidth / 2)
|
|
|
|
pos_surface.z = pos_surface.z - math.ceil(fdepth / 2)
|
|
|
|
-- to find the y position, also check the corners
|
|
|
|
local ys = {pos_surface.y}
|
|
|
|
local pos_c
|
|
|
|
pos_c = mcl_villages.find_surface_down(vector.new(pos_surface.x-1, pos_surface.y+fheight, pos_surface.z-1))
|
|
|
|
if pos_c then table.insert(ys, pos_c.y) end
|
|
|
|
pos_c = mcl_villages.find_surface_down(vector.new(pos_surface.x+fwidth+2, pos_surface.y+fheight, pos_surface.z-1))
|
|
|
|
if pos_c then table.insert(ys, pos_c.y) end
|
|
|
|
pos_c = mcl_villages.find_surface_down(vector.new(pos_surface.x-1, pos_surface.y+fheight, pos_surface.z+fdepth+2))
|
|
|
|
if pos_c then table.insert(ys, pos_c.y) end
|
|
|
|
pos_c = mcl_villages.find_surface_down(vector.new(pos_surface.x+fwidth+2, pos_surface.y+fheight, pos_surface.z+fdepth+2))
|
|
|
|
if pos_c then table.insert(ys, pos_c.y) end
|
|
|
|
table.sort(ys)
|
|
|
|
-- well supported base, not too uneven?
|
|
|
|
if #ys < 5 or ys[#ys]-ys[1] > fheight + 3 then return nil end
|
|
|
|
pos_surface.y = ys[math.ceil(#ys/2)]
|
|
|
|
-- check distance to other buildings
|
|
|
|
if mcl_villages.check_distance(settlement_info, pos_surface, building_all_info["hsize"]) then
|
|
|
|
return pos_surface
|
|
|
|
end
|
|
|
|
return nil
|
|
|
|
end
|
2021-01-27 09:56:53 +01:00
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- fill settlement_info
|
|
|
|
--------------------------------------------------------------------------------
|
2024-07-19 14:56:06 +02:00
|
|
|
function mcl_villages.create_site_plan(minp, maxp, pr)
|
|
|
|
local center = vector.new(math.floor((minp.x+maxp.x)/2),maxp.y,math.floor((minp.z+maxp.z)/2))
|
|
|
|
minetest.log("action", "sudo make me a village at: " .. minetest.pos_to_string(center))
|
2021-01-27 09:56:53 +01:00
|
|
|
local possible_rotations = {"0", "90", "180", "270"}
|
2024-07-19 14:56:06 +02:00
|
|
|
local center_surface
|
2023-01-03 19:32:52 +01:00
|
|
|
|
2024-07-19 14:56:06 +02:00
|
|
|
local count_buildings, number_of_buildings, number_built = mcl_villages.initialize_settlement_info(pr)
|
|
|
|
local settlement_info = {}
|
2021-01-27 09:56:53 +01:00
|
|
|
-- now some buildings around in a circle, radius = size of town center
|
2024-07-19 14:56:06 +02:00
|
|
|
local x, y, z, r = center.x, maxp.y, center.z, 0
|
2021-01-27 09:56:53 +01:00
|
|
|
-- draw j circles around center and increase radius by math.random(2,5)
|
2024-07-19 14:56:06 +02:00
|
|
|
for j = 1,10 do
|
|
|
|
for angle = 0, math.pi*2, 0.262 do -- 24 attempts on a circle
|
|
|
|
local pos1 = vector.new(math.floor(x + r * math.cos(angle) + 0.5), y, math.floor(z - r * math.sin(angle) + 0.5))
|
|
|
|
local pos_surface, surface_material = mcl_villages.find_surface(pos1, false)
|
|
|
|
if pos_surface then
|
|
|
|
local randomized_schematic_table = mcl_villages.shuffle(mcl_villages.schematic_table, pr)
|
|
|
|
if #settlement_info == 0 then randomized_schematic_table = { mcl_villages.schematic_table[1] } end -- place town bell first
|
|
|
|
-- pick schematic
|
|
|
|
local size = #randomized_schematic_table
|
|
|
|
for i = 1, #randomized_schematic_table do
|
|
|
|
local building_all_info = randomized_schematic_table[i]
|
|
|
|
-- already enough buildings of that type?
|
|
|
|
if count_buildings[building_all_info["name"]] < building_all_info["max_num"]*number_of_buildings then
|
|
|
|
local rotation = possible_rotations[pr:next(1, #possible_rotations)]
|
|
|
|
local pos = try_place_building(pos_surface, building_all_info, rotation, settlement_info, pr)
|
|
|
|
if pos then
|
|
|
|
if #settlement_info == 0 then -- town bell
|
|
|
|
center_surface, y = pos, pos.y + max_height_difference
|
|
|
|
end
|
|
|
|
-- limit height differences to town center
|
|
|
|
if math.abs(pos.y - center_surface.y) > max_height_difference * 0.7 then
|
|
|
|
break -- other buildings likely will not fit either
|
|
|
|
end
|
|
|
|
count_buildings[building_all_info["name"]] = count_buildings[building_all_info["name"]] +1
|
|
|
|
number_built = number_built + 1
|
2021-01-27 09:56:53 +01:00
|
|
|
|
2024-07-19 14:56:06 +02:00
|
|
|
pos.y = pos.y + (building_all_info["yadjust"] or 0)
|
|
|
|
table.insert(settlement_info, {
|
|
|
|
pos = pos,
|
|
|
|
name = building_all_info["name"],
|
|
|
|
hsize = building_all_info["hsize"],
|
|
|
|
rotat = rotation,
|
|
|
|
surface_mat = surface_material
|
|
|
|
})
|
|
|
|
-- minetest.log("action", "Placing "..building_all_info["name"].." at "..minetest.pos_to_string(pos))
|
|
|
|
break
|
|
|
|
end
|
2021-01-27 09:56:53 +01:00
|
|
|
end
|
|
|
|
end
|
2024-07-19 14:56:06 +02:00
|
|
|
if number_of_buildings == number_built then
|
|
|
|
break
|
|
|
|
end
|
2021-01-27 09:56:53 +01:00
|
|
|
end
|
2024-07-19 14:56:06 +02:00
|
|
|
if r == 0 then break end -- no angles in the very center
|
2021-02-22 00:15:32 +01:00
|
|
|
end
|
|
|
|
if number_built >= number_of_buildings then
|
|
|
|
break
|
2021-01-27 09:56:53 +01:00
|
|
|
end
|
2021-02-22 00:15:32 +01:00
|
|
|
r = r + pr:next(2,5)
|
2024-07-19 14:56:06 +02:00
|
|
|
if r > 35 then break end -- avoid touching neighboring blocks
|
|
|
|
end
|
|
|
|
mcl_villages.debug("really ".. number_built)
|
|
|
|
if number_built <= 8 then
|
|
|
|
minetest.log("action", "Bad village location, could only place "..number_built.." buildings.")
|
|
|
|
return
|
2021-01-27 09:56:53 +01:00
|
|
|
end
|
2024-07-19 14:56:06 +02:00
|
|
|
minetest.log("action", "Village completed at " .. minetest.pos_to_string(center))
|
|
|
|
minetest.log("Village completed at " .. minetest.pos_to_string(center)) -- for debugging only
|
2021-01-27 09:56:53 +01:00
|
|
|
return settlement_info
|
|
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- evaluate settlement_info and place schematics
|
|
|
|
-------------------------------------------------------------------------------
|
2021-02-27 00:33:51 +01:00
|
|
|
-- Initialize node
|
|
|
|
local function construct_node(p1, p2, name)
|
|
|
|
local r = minetest.registered_nodes[name]
|
|
|
|
if r then
|
|
|
|
if r.on_construct then
|
|
|
|
local nodes = minetest.find_nodes_in_area(p1, p2, name)
|
|
|
|
for p=1, #nodes do
|
|
|
|
local pos = nodes[p]
|
|
|
|
r.on_construct(pos)
|
|
|
|
end
|
|
|
|
return nodes
|
|
|
|
end
|
2021-05-29 16:12:33 +02:00
|
|
|
minetest.log("warning", "[mcl_villages] No on_construct defined for node name " .. name)
|
2021-02-27 00:33:51 +01:00
|
|
|
return
|
|
|
|
end
|
2021-05-29 16:12:33 +02:00
|
|
|
minetest.log("warning", "[mcl_villages] Attempt to 'construct' inexistant nodes: " .. name)
|
2021-02-27 00:33:51 +01:00
|
|
|
end
|
2022-05-20 23:44:58 +02:00
|
|
|
|
|
|
|
local function spawn_iron_golem(pos)
|
2023-01-03 19:32:52 +01:00
|
|
|
--minetest.log("action", "Attempt to spawn iron golem.")
|
2022-05-20 23:44:58 +02:00
|
|
|
local p = minetest.find_node_near(pos,50,"mcl_core:grass_path")
|
|
|
|
if p then
|
2024-07-19 14:56:06 +02:00
|
|
|
p.y = p.y + 1
|
2022-05-20 23:44:58 +02:00
|
|
|
local l=minetest.add_entity(p,"mobs_mc:iron_golem"):get_luaentity()
|
|
|
|
if l then
|
|
|
|
l._home = p
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function spawn_villagers(minp,maxp)
|
2023-01-03 19:32:52 +01:00
|
|
|
--minetest.log("action", "Attempt to spawn villagers.")
|
2022-05-21 13:43:28 +02:00
|
|
|
local beds=minetest.find_nodes_in_area(vector.offset(minp,-20,-20,-20),vector.offset(maxp,20,20,20),{"mcl_beds:bed_red_bottom"})
|
2022-05-20 23:44:58 +02:00
|
|
|
for _,bed in pairs(beds) do
|
|
|
|
local m = minetest.get_meta(bed)
|
|
|
|
if m:get_string("villager") == "" then
|
|
|
|
local v=minetest.add_entity(bed,"mobs_mc:villager")
|
|
|
|
if v then
|
|
|
|
local l=v:get_luaentity()
|
|
|
|
l._bed = bed
|
|
|
|
m:set_string("villager",l._id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-02-18 14:51:31 +01:00
|
|
|
local function fix_village_water(minp,maxp)
|
|
|
|
local palettenodes = minetest.find_nodes_in_area(vector.offset(minp,-20,-20,-20),vector.offset(maxp,20,20,20), "group:water_palette")
|
|
|
|
for _, palettenodepos in pairs(palettenodes) do
|
|
|
|
local palettenode = minetest.get_node(palettenodepos)
|
|
|
|
minetest.set_node(palettenodepos, {name = palettenode.name})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-02-27 00:33:51 +01:00
|
|
|
local function init_nodes(p1, p2, size, rotation, pr)
|
|
|
|
construct_node(p1, p2, "mcl_itemframes:item_frame")
|
|
|
|
construct_node(p1, p2, "mcl_furnaces:furnace")
|
|
|
|
construct_node(p1, p2, "mcl_anvils:anvil")
|
|
|
|
|
2022-05-20 18:50:18 +02:00
|
|
|
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")
|
2021-02-27 00:33:51 +01:00
|
|
|
local nodes = construct_node(p1, p2, "mcl_chests:chest")
|
|
|
|
if nodes and #nodes > 0 then
|
|
|
|
for p=1, #nodes do
|
|
|
|
local pos = nodes[p]
|
2024-07-19 14:56:06 +02:00
|
|
|
mcl_villages.fill_chest(pos, pr)
|
2021-02-27 00:33:51 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-05-20 23:44:58 +02:00
|
|
|
|
2024-07-19 14:56:06 +02:00
|
|
|
function mcl_villages.place_schematics(settlement_info, pr)
|
2021-01-27 09:56:53 +01:00
|
|
|
local building_all_info
|
2024-07-19 14:56:06 +02:00
|
|
|
local lvm = VoxelManip()
|
2022-05-26 07:29:28 +02:00
|
|
|
|
2021-01-27 09:56:53 +01:00
|
|
|
for i, built_house in ipairs(settlement_info) do
|
2022-05-20 23:44:58 +02:00
|
|
|
local is_last = i == #settlement_info
|
2022-05-26 07:29:28 +02:00
|
|
|
|
2024-07-19 14:56:06 +02:00
|
|
|
for j, schem in ipairs(mcl_villages.schematic_table) do
|
2021-01-27 09:56:53 +01:00
|
|
|
if settlement_info[i]["name"] == schem["name"] then
|
|
|
|
building_all_info = schem
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-04-17 07:42:49 +02:00
|
|
|
local pos = settlement_info[i]["pos"]
|
|
|
|
local rotation = settlement_info[i]["rotat"]
|
2021-01-27 09:56:53 +01:00
|
|
|
-- get building node material for better integration to surrounding
|
2024-07-19 14:56:06 +02:00
|
|
|
local surface_material = settlement_info[i]["surface_mat"] or "mcl_core:stone"
|
|
|
|
local platform_material = surface_material
|
|
|
|
local schem_lua = building_all_info["schem_lua"]
|
|
|
|
if not schem_lua then
|
|
|
|
schem_lua = minetest.serialize_schematic(building_all_info["mts"], "lua", { lua_use_comments = false, lua_num_indent_spaces = 0 }) .. " return schematic"
|
|
|
|
building_all_info["schem_lua"] = schem_lua
|
2021-01-27 09:56:53 +01:00
|
|
|
end
|
2024-07-19 14:56:06 +02:00
|
|
|
schem_lua = schem_lua:gsub('"mcl_core:dirt"', '"'..platform_material..'"')
|
|
|
|
schem_lua = schem_lua:gsub('"mcl_core:dirt_with_grass"', '"'..surface_material..'"')
|
|
|
|
local schematic = loadstring(mcl_villages.substitute_materials(pos, schem_lua, pr))()
|
2023-02-18 14:51:31 +01:00
|
|
|
|
2023-01-03 19:32:52 +01:00
|
|
|
local is_belltower = building_all_info["name"] == "belltower"
|
|
|
|
|
2024-07-19 14:56:06 +02:00
|
|
|
-- already built the foundation for the building and made room above
|
|
|
|
local sx, sy, sz = schematic.size.x, schematic.size.y, schematic.size.z
|
|
|
|
local p2 = vector.new(pos.x+sx-1,pos.y+sy-1,pos.z+sz-1)
|
|
|
|
lvm:read_from_map(pos, p2)
|
|
|
|
minetest.place_schematic_on_vmanip(
|
|
|
|
lvm,
|
2021-04-17 07:42:49 +02:00
|
|
|
pos,
|
|
|
|
schematic,
|
|
|
|
rotation,
|
|
|
|
nil,
|
2021-02-27 00:33:51 +01:00
|
|
|
true,
|
2024-07-19 14:56:06 +02:00
|
|
|
{ place_center_x = false, place_center_y = false, place_center_z = false }
|
2021-02-27 00:33:51 +01:00
|
|
|
)
|
2024-07-19 14:56:06 +02:00
|
|
|
lvm:write_to_map(true) -- FIXME: postpone
|
|
|
|
if rotation == "90" or rotation == "270" then sx, sz = sz, sx end
|
|
|
|
init_nodes(pos, p2, schematic.size, rotation, pr)
|
|
|
|
|
|
|
|
if is_belltower then
|
|
|
|
spawn_iron_golem(pos)
|
|
|
|
else
|
|
|
|
spawn_villagers(pos,p2)
|
|
|
|
fix_village_water(pos,p2)
|
|
|
|
end
|
2021-01-27 09:56:53 +01:00
|
|
|
end
|
|
|
|
end
|