2021-01-27 09:56:53 +01:00
--[[
-------------------------------------------------------------------------------
-- build schematic, replace material, rotation
-------------------------------------------------------------------------------
function settlements . build_schematic ( vm , data , va , pos , building , replace_wall , name )
-- 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 ) ]
settlements.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
-------------------------------------------------------------------------------
function settlements . initialize_settlement_info ( pr )
local count_buildings = { }
-- count_buildings table reset
2021-01-29 19:49:33 +01:00
for k , v in pairs ( settlements.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 )
local number_built = 1
settlements.debug ( " Village " .. number_of_buildings )
return count_buildings , number_of_buildings , number_built
end
-------------------------------------------------------------------------------
-- fill settlement_info
--------------------------------------------------------------------------------
function settlements . create_site_plan ( maxp , minp , pr )
local settlement_info = { }
local building_all_info
local possible_rotations = { " 0 " , " 90 " , " 180 " , " 270 " }
2023-01-03 19:32:52 +01:00
2021-01-27 09:56:53 +01:00
-- find center of chunk
local center = {
2021-04-17 07:42:49 +02:00
x = math.floor ( ( minp.x + maxp.x ) / 2 ) ,
y = maxp.y ,
2021-02-22 00:15:32 +01:00
z = math.floor ( ( minp.z + maxp.z ) / 2 )
2021-04-17 07:46:24 +02:00
}
2023-01-03 19:32:52 +01:00
2021-01-27 09:56:53 +01:00
-- find center_surface of chunk
2021-02-22 00:15:32 +01:00
local center_surface , surface_material = settlements.find_surface ( center , true )
local chunks = { }
chunks [ mcl_vars.get_chunk_number ( center ) ] = true
2021-01-27 09:56:53 +01:00
-- go build settlement around center
2023-01-03 19:32:52 +01:00
if not center_surface then
minetest.log ( " action " , " Cannot build village at: " .. minetest.pos_to_string ( center ) )
return false
else
minetest.log ( " action " , " Village built. " )
--minetest.log("action", "Build village at: " .. minetest.pos_to_string(center) .. " with surface material: " .. surface_material)
end
2021-01-27 09:56:53 +01:00
-- initialize all settlement_info table
local count_buildings , number_of_buildings , number_built = settlements.initialize_settlement_info ( pr )
-- first building is townhall in the center
2021-01-29 19:49:33 +01:00
building_all_info = settlements.schematic_table [ 1 ]
2021-01-27 09:56:53 +01:00
local rotation = possible_rotations [ pr : next ( 1 , # possible_rotations ) ]
-- add to settlement info table
local index = 1
settlement_info [ index ] = {
2021-04-17 07:42:49 +02:00
pos = center_surface ,
name = building_all_info [ " name " ] ,
2021-01-27 09:56:53 +01:00
hsize = building_all_info [ " hsize " ] ,
rotat = rotation ,
surface_mat = surface_material
}
--increase index for following buildings
index = index + 1
-- now some buildings around in a circle, radius = size of town center
local x , z , r = center_surface.x , center_surface.z , building_all_info [ " hsize " ]
-- draw j circles around center and increase radius by math.random(2,5)
for j = 1 , 20 do
2021-02-22 00:15:32 +01:00
-- set position on imaginary circle
for j = 0 , 360 , 15 do
local angle = j * math.pi / 180
local ptx , ptz = x + r * math.cos ( angle ) , z + r * math.sin ( angle )
ptx = settlements.round ( ptx , 0 )
ptz = settlements.round ( ptz , 0 )
local pos1 = { x = ptx , y = center_surface.y + 50 , z = ptz }
local chunk_number = mcl_vars.get_chunk_number ( pos1 )
local pos_surface , surface_material
if chunks [ chunk_number ] then
pos_surface , surface_material = settlements.find_surface ( pos1 )
else
chunks [ chunk_number ] = true
pos_surface , surface_material = settlements.find_surface ( pos1 , true )
end
if not pos_surface then break end
2021-01-27 09:56:53 +01:00
2021-02-22 00:15:32 +01:00
local randomized_schematic_table = shuffle ( settlements.schematic_table , pr )
-- pick schematic
local size = # randomized_schematic_table
for i = size , 1 , - 1 do
-- already enough buildings of that type?
if count_buildings [ randomized_schematic_table [ i ] [ " name " ] ] < randomized_schematic_table [ i ] [ " max_num " ] * number_of_buildings then
building_all_info = randomized_schematic_table [ i ]
-- check distance to other buildings
local distance_to_other_buildings_ok = settlements.check_distance ( settlement_info , pos_surface , building_all_info [ " hsize " ] )
if distance_to_other_buildings_ok then
-- count built houses
count_buildings [ building_all_info [ " name " ] ] = count_buildings [ building_all_info [ " name " ] ] + 1
rotation = possible_rotations [ pr : next ( 1 , # possible_rotations ) ]
number_built = number_built + 1
settlement_info [ index ] = {
2021-04-17 07:42:49 +02:00
pos = pos_surface ,
name = building_all_info [ " name " ] ,
2021-02-22 00:15:32 +01:00
hsize = building_all_info [ " hsize " ] ,
rotat = rotation ,
surface_mat = surface_material
}
index = index + 1
break
2021-01-27 09:56:53 +01:00
end
end
end
2021-02-22 00:15:32 +01:00
if number_of_buildings == number_built then
break
end
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 )
2021-01-27 09:56:53 +01:00
end
settlements.debug ( " really " .. number_built )
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
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 ]
settlements.fill_chest ( pos , pr )
end
end
end
2022-05-20 23:44:58 +02:00
2021-01-27 09:56:53 +01:00
function settlements . place_schematics ( settlement_info , pr )
local building_all_info
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
2021-01-29 19:49:33 +01:00
for j , schem in ipairs ( settlements.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
2023-01-03 19:32:52 +01:00
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
2021-04-17 07:42:49 +02:00
local platform_material = settlement_info [ i ] [ " surface_mat " ]
2021-01-27 09:56:53 +01:00
--platform_material_name = minetest.get_name_from_content_id(platform_material)
-- pick random material
2021-01-29 06:59:01 +01:00
--local material = wallmaterial[pr:next(1,#wallmaterial)]
2021-01-27 09:56:53 +01:00
--
local building = building_all_info [ " mts " ]
local replace_wall = building_all_info [ " rplc " ]
-- 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-02-09 13:06:19 +01:00
schem_lua = schem_lua : gsub ( " mcl_core:stonebrickcarved " , " mcl_villages:stonebrickcarved " )
2021-01-27 09:56:53 +01:00
-- replace material
2021-01-29 19:49:33 +01:00
if replace_wall then
2021-01-29 06:59:01 +01:00
--Note, block substitution isn't matching node names exactly; so nodes that are to be substituted that have the same prefixes cause bugs.
-- Example: Attempting to swap out 'mcl_core:stonebrick'; which has multiple, additional sub-variants: (carved, cracked, mossy). Will currently cause issues, so leaving disabled.
if platform_material == " mcl_core:snow " or platform_material == " mcl_core:dirt_with_grass_snow " or platform_material == " mcl_core:podzol " then
schem_lua = schem_lua : gsub ( " mcl_core:tree " , " mcl_core:sprucetree " )
schem_lua = schem_lua : gsub ( " mcl_core:wood " , " mcl_core:sprucewood " )
--schem_lua = schem_lua:gsub("mcl_fences:fence", "mcl_fences:spruce_fence")
--schem_lua = schem_lua:gsub("mcl_stairs:slab_wood_top", "mcl_stairs:slab_sprucewood_top")
--schem_lua = schem_lua:gsub("mcl_stairs:stair_wood", "mcl_stairs:stair_sprucewood")
--schem_lua = schem_lua:gsub("mesecons_pressureplates:pressure_plate_wood_off", "mesecons_pressureplates:pressure_plate_sprucewood_off")
elseif platform_material == " mcl_core:sand " or platform_material == " mcl_core:redsand " then
schem_lua = schem_lua : gsub ( " mcl_core:tree " , " mcl_core:sandstonecarved " )
2024-06-15 00:51:37 +02:00
schem_lua = schem_lua : gsub ( " blocks:cobblestone " , " mcl_core:sandstone " )
2021-01-29 06:59:01 +01:00
schem_lua = schem_lua : gsub ( " mcl_core:wood " , " mcl_core:sandstonesmooth " )
--schem_lua = schem_lua:gsub("mcl_fences:fence", "mcl_fences:birch_fence")
--schem_lua = schem_lua:gsub("mcl_stairs:slab_wood_top", "mcl_stairs:slab_birchwood_top")
--schem_lua = schem_lua:gsub("mcl_stairs:stair_wood", "mcl_stairs:stair_birchwood")
--schem_lua = schem_lua:gsub("mesecons_pressureplates:pressure_plate_wood_off", "mesecons_pressureplates:pressure_plate_birchwood_off")
--schem_lua = schem_lua:gsub("mcl_stairs:stair_stonebrick", "mcl_stairs:stair_redsandstone")
--schem_lua = schem_lua:gsub("mcl_core:stonebrick", "mcl_core:redsandstonesmooth")
schem_lua = schem_lua : gsub ( " mcl_core:brick_block " , " mcl_core:redsandstone " )
end
2021-01-27 09:56:53 +01:00
end
schem_lua = schem_lua : gsub ( " mcl_core:dirt_with_grass " , platform_material )
--[[ Disable special junglewood for now.
-- special material for spawning npcs
schem_lua = schem_lua : gsub ( " mcl_core:junglewood " , " settlements:junglewood " )
--]]
schem_lua = schem_lua : gsub ( " mcl_stairs:stair_wood_outer " , " mcl_stairs:slab_wood " )
schem_lua = schem_lua : gsub ( " mcl_stairs:stair_stone_rough_outer " , " air " )
-- format schematic string
local schematic = loadstring ( schem_lua ) ( )
2023-02-18 14:51:31 +01:00
2023-01-03 19:32:52 +01:00
local is_belltower = building_all_info [ " name " ] == " belltower "
2021-01-27 09:56:53 +01:00
-- build foundation for the building an make room above
2023-01-03 19:32:52 +01:00
2021-02-24 22:03:41 +01:00
mcl_structures.place_schematic (
2021-04-17 07:42:49 +02:00
pos ,
schematic ,
rotation ,
nil ,
2021-02-27 00:33:51 +01:00
true ,
nil ,
2022-05-20 23:44:58 +02:00
function ( p1 , p2 , size , rotation , pr )
2023-01-03 19:32:52 +01:00
if is_belltower then
spawn_iron_golem ( p1 )
else
init_nodes ( p1 , p2 , size , rotation , pr )
spawn_villagers ( p1 , p2 )
2023-02-18 14:51:31 +01:00
fix_village_water ( p1 , p2 )
2023-01-03 19:32:52 +01:00
end
2022-05-20 23:44:58 +02:00
end ,
2021-02-27 00:33:51 +01:00
pr
)
2021-01-27 09:56:53 +01:00
end
end