mirror of
https://git.minetest.land/MineClone2/MineClone2.git
synced 2024-11-24 20:03:45 +01:00
333 lines
12 KiB
Lua
333 lines
12 KiB
Lua
--[[
|
|
-------------------------------------------------------------------------------
|
|
-- 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
|
|
local platform_material = mcl_vars.get_node(pos)
|
|
if not platform_material or (platform_material.name == "air" or platform_material.name == "ignore") then
|
|
return
|
|
end
|
|
platform_material = platform_material.name
|
|
-- pick random material
|
|
local material = wallmaterial[math.random(1,#wallmaterial)]
|
|
-- schematic conversion to lua
|
|
local schem_lua = minetest.serialize_schematic(building,
|
|
"lua",
|
|
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return schematic"
|
|
-- replace material
|
|
if replace_wall == "y" then
|
|
schem_lua = schem_lua:gsub("mcl_core:cobble", material)
|
|
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")
|
|
--
|
|
|
|
-- 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(
|
|
pos,
|
|
width,
|
|
depth,
|
|
height,
|
|
rotation)
|
|
vm:set_data(data)
|
|
-- place schematic
|
|
|
|
minetest.place_schematic_on_vmanip(
|
|
vm,
|
|
pos,
|
|
schematic,
|
|
rotation,
|
|
nil,
|
|
true)
|
|
vm:write_to_map(true)
|
|
end]]
|
|
-------------------------------------------------------------------------------
|
|
-- initialize settlement_info
|
|
-------------------------------------------------------------------------------
|
|
function settlements.initialize_settlement_info(pr)
|
|
local count_buildings = {}
|
|
|
|
-- count_buildings table reset
|
|
for k,v in pairs(settlements.schematic_table) do
|
|
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"}
|
|
-- find center of chunk
|
|
local center = {
|
|
x=math.floor((minp.x+maxp.x)/2),
|
|
y=maxp.y,
|
|
z=math.floor((minp.z+maxp.z)/2)
|
|
}
|
|
-- find center_surface of chunk
|
|
local center_surface , surface_material = settlements.find_surface(center, true)
|
|
local chunks = {}
|
|
chunks[mcl_vars.get_chunk_number(center)] = true
|
|
|
|
-- go build settlement around center
|
|
if not center_surface then return false end
|
|
|
|
-- 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
|
|
building_all_info = settlements.schematic_table[1]
|
|
local rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
|
-- add to settlement info table
|
|
local index = 1
|
|
settlement_info[index] = {
|
|
pos = center_surface,
|
|
name = building_all_info["name"],
|
|
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
|
|
-- 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
|
|
|
|
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] = {
|
|
pos = pos_surface,
|
|
name = building_all_info["name"],
|
|
hsize = building_all_info["hsize"],
|
|
rotat = rotation,
|
|
surface_mat = surface_material
|
|
}
|
|
index = index + 1
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if number_of_buildings == number_built then
|
|
break
|
|
end
|
|
end
|
|
if number_built >= number_of_buildings then
|
|
break
|
|
end
|
|
r = r + pr:next(2,5)
|
|
end
|
|
settlements.debug("really ".. number_built)
|
|
return settlement_info
|
|
end
|
|
-------------------------------------------------------------------------------
|
|
-- evaluate settlement_info and place schematics
|
|
-------------------------------------------------------------------------------
|
|
-- 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
|
|
minetest.log("warning", "[mcl_villages] No on_construct defined for node name " .. name)
|
|
return
|
|
end
|
|
minetest.log("warning", "[mcl_villages] Attempt to 'construct' inexistant nodes: " .. name)
|
|
end
|
|
|
|
local function spawn_iron_golem(pos)
|
|
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)
|
|
local beds=minetest.find_nodes_in_area(vector.offset(minp,-20,-20,-20),vector.offset(maxp,20,20,20),{"mcl_beds:bed_red_bottom"})
|
|
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
|
|
|
|
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")
|
|
|
|
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")
|
|
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
|
|
|
|
function settlements.place_schematics(settlement_info, pr)
|
|
local building_all_info
|
|
|
|
--attempt to place one belltower in the center of the village - this doesn't always work out great but it's a lot better than doing it first or last.
|
|
local belltower = table.remove(settlement_info,math.floor(#settlement_info/2))
|
|
if belltower then
|
|
mcl_structures.place_schematic(
|
|
vector.offset(belltower["pos"],0,0,0),
|
|
settlements.modpath.."/schematics/belltower.mts",
|
|
belltower["rotation"],
|
|
nil,
|
|
true,
|
|
nil,
|
|
function(p1, p2, size, rotation, pr)
|
|
spawn_iron_golem(p1)
|
|
end,
|
|
pr
|
|
)
|
|
end
|
|
|
|
for i, built_house in ipairs(settlement_info) do
|
|
local is_last = i == #settlement_info
|
|
|
|
for j, schem in ipairs(settlements.schematic_table) do
|
|
if settlement_info[i]["name"] == schem["name"] then
|
|
building_all_info = schem
|
|
break
|
|
end
|
|
end
|
|
|
|
local pos = settlement_info[i]["pos"]
|
|
local rotation = settlement_info[i]["rotat"]
|
|
-- get building node material for better integration to surrounding
|
|
local platform_material = settlement_info[i]["surface_mat"]
|
|
--platform_material_name = minetest.get_name_from_content_id(platform_material)
|
|
-- pick random material
|
|
--local material = wallmaterial[pr:next(1,#wallmaterial)]
|
|
--
|
|
local building = building_all_info["mts"]
|
|
local replace_wall = building_all_info["rplc"]
|
|
-- schematic conversion to lua
|
|
local schem_lua = minetest.serialize_schematic(building,
|
|
"lua",
|
|
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return schematic"
|
|
schem_lua = schem_lua:gsub("mcl_core:stonebrickcarved", "mcl_villages:stonebrickcarved")
|
|
-- replace material
|
|
if replace_wall then
|
|
--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")
|
|
schem_lua = schem_lua:gsub("mcl_core:cobble", "mcl_core:sandstone")
|
|
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
|
|
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)()
|
|
-- build foundation for the building an make room above
|
|
-- place schematic
|
|
mcl_structures.place_schematic(
|
|
pos,
|
|
schematic,
|
|
rotation,
|
|
nil,
|
|
true,
|
|
nil,
|
|
function(p1, p2, size, rotation, pr)
|
|
init_nodes(p1, p2, size, rotation, pr)
|
|
spawn_villagers(p1,p2)
|
|
end,
|
|
pr
|
|
)
|
|
end
|
|
end
|