Add mcl_villages; with support for seed-based, and multithreaded village generation by kay27.
This commit is contained in:
parent
9feee980f8
commit
0c23406531
|
@ -0,0 +1,45 @@
|
|||
MCL_Villages:
|
||||
============================
|
||||
A fork of Rochambeau's "Settlements" mod converted for use in MineClone2.
|
||||
|
||||
--------------
|
||||
Using the mod:
|
||||
--------------
|
||||
This mod adds settlements on world generation.
|
||||
|
||||
And, in Creative Mode; also comes with a debug tool for spawning in villages.
|
||||
|
||||
|
||||
-------------
|
||||
MCL2 Credits:
|
||||
-------------
|
||||
Code forked from: https://github.com/MysticTempest/settlements/tree/mcl_villages
|
||||
Commit: e24b4be
|
||||
================================================================================
|
||||
Basic conversion of Settlements mod for compatibility with MineClone2, plus new schematics: MysticTempest
|
||||
|
||||
Seed-based Village Generation, multi-threading, bugfixes: kay27
|
||||
|
||||
|
||||
|
||||
=========================
|
||||
version: 0.1 alpha
|
||||
|
||||
License of source code: WTFPL
|
||||
-----------------------------
|
||||
(c) Copyright Rochambeau (2018)
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
|
||||
Credits:
|
||||
--------------
|
||||
This mod is based on "ruins" by BlockMen
|
||||
|
||||
Completely new schematics for MineClone2:
|
||||
MysticTempest - CC-BY-SA 4.0
|
||||
|
|
@ -0,0 +1,357 @@
|
|||
--[[
|
||||
-------------------------------------------------------------------------------
|
||||
-- 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 = minetest.get_node_or_nil(pos)
|
||||
if not platform_material 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(schematic_table) do
|
||||
-- local name = schematic_table[v]["name"]
|
||||
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 with LVM
|
||||
--------------------------------------------------------------------------------
|
||||
function settlements.create_site_plan_lvm(maxp, minp, pr)
|
||||
local settlement_info = {}
|
||||
local building_all_info
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
-- find center of chunk
|
||||
local center = {
|
||||
x=maxp.x-half_map_chunk_size,
|
||||
y=maxp.y,
|
||||
z=maxp.z-half_map_chunk_size
|
||||
}
|
||||
-- find center_surface of chunk
|
||||
local center_surface, surface_material = settlements.find_surface_lvm(center, minp)
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
|
||||
-- add settlement to list
|
||||
table.insert(settlements_in_world, center_surface)
|
||||
-- save list to file
|
||||
settlements.save()
|
||||
-- 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 = 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
|
||||
if number_built < number_of_buildings then
|
||||
-- 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 pos_surface, surface_material = settlements.find_surface_lvm(pos1, minp)
|
||||
if not pos_surface then break end
|
||||
|
||||
local randomized_schematic_table = shuffle(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
|
||||
r = r + pr:next(2,5)
|
||||
end
|
||||
end
|
||||
settlements.debug("really ".. number_built)
|
||||
return settlement_info
|
||||
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=maxp.x-half_map_chunk_size,
|
||||
y=maxp.y,
|
||||
z=maxp.z-half_map_chunk_size
|
||||
}
|
||||
-- find center_surface of chunk
|
||||
local center_surface , surface_material = settlements.find_surface(center)
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
|
||||
-- add settlement to list
|
||||
table.insert(settlements_in_world, center_surface)
|
||||
-- save list to file
|
||||
settlements.save()
|
||||
-- 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 = 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
|
||||
if number_built < number_of_buildings then
|
||||
-- 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 pos_surface, surface_material = settlements.find_surface(pos1)
|
||||
if not pos_surface then break end
|
||||
|
||||
local randomized_schematic_table = shuffle(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
|
||||
r = r + pr:next(2,5)
|
||||
end
|
||||
end
|
||||
settlements.debug("really ".. number_built)
|
||||
return settlement_info
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate settlement_info and place schematics
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.place_schematics_lvm(settlement_info, pr)
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
for j, schem in ipairs(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)"
|
||||
-- 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_name)
|
||||
|
||||
--[[ 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
|
||||
-- place schematic
|
||||
|
||||
minetest.place_schematic_on_vmanip(
|
||||
vm,
|
||||
pos,
|
||||
schematic,
|
||||
rotation,
|
||||
nil,
|
||||
true)
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate settlement_info and place schematics
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.place_schematics(settlement_info, pr)
|
||||
local building_all_info
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
for j, schem in ipairs(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)"
|
||||
-- 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")
|
||||
--]]
|
||||
|
||||
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
|
||||
minetest.place_schematic(
|
||||
pos,
|
||||
schematic,
|
||||
rotation,
|
||||
nil,
|
||||
true)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,83 @@
|
|||
-- switch for debugging
|
||||
settlements.debug = function(message)
|
||||
-- minetest.chat_send_all(message)
|
||||
-- minetest.log("warning", "[mcl_villages] "..message)
|
||||
minetest.log("verbose", "[mcl_villages] "..message)
|
||||
end
|
||||
|
||||
-- switch for lvm
|
||||
settlements.lvm = false
|
||||
|
||||
settlements.last_settlement = os.time()
|
||||
|
||||
-- material to replace cobblestone with
|
||||
wallmaterial = {
|
||||
"mcl_core:junglewood",
|
||||
"mcl_core:sprucewood",
|
||||
"mcl_core:wood",
|
||||
"mcl_core:birchwood",
|
||||
"mcl_core:acaciawood",
|
||||
"mcl_core:stonebrick",
|
||||
"mcl_core:cobble",
|
||||
"mcl_core:sandstonecarved",
|
||||
"mcl_core:sandstone",
|
||||
"mcl_core:sandstonesmooth2"
|
||||
}
|
||||
settlements.surface_mat = {}
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.grundstellungen()
|
||||
settlements.surface_mat = settlements.Set {
|
||||
"mcl_core:dirt_with_grass",
|
||||
--"mcl_core:dry_dirt_with_grass",
|
||||
"mcl_core:dirt_with_grass_snow",
|
||||
--"mcl_core:dirt_with_dry_grass",
|
||||
"mcl_core:podzol",
|
||||
"mcl_core:sand",
|
||||
"mcl_core:redsand",
|
||||
--"mcl_core:silver_sand",
|
||||
"mcl_core:snowblock"
|
||||
}
|
||||
end
|
||||
--
|
||||
-- possible surfaces where buildings can be built
|
||||
--
|
||||
|
||||
--
|
||||
-- path to schematics
|
||||
--
|
||||
schem_path = settlements.modpath.."/schematics/"
|
||||
--
|
||||
-- list of schematics
|
||||
--
|
||||
schematic_table = {
|
||||
{name = "large_house", mts = schem_path.."large_house.mts", hwidth = 11, hdepth = 12, hheight = 9, hsize = 14, max_num = 0.08, rplc = "n"},
|
||||
{name = "blacksmith", mts = schem_path.."blacksmith.mts", hwidth = 7, hdepth = 7, hheight = 13, hsize = 13, max_num = 0.050, rplc = "n"},
|
||||
{name = "church", mts = schem_path.."church.mts", hwidth = 13, hdepth = 13, hheight = 14, hsize = 15, max_num = 0.04, rplc = "n"},
|
||||
{name = "farm", mts = schem_path.."farm.mts", hwidth = 7, hdepth = 7, hheight = 13, hsize = 13, max_num = 0.1, rplc = "n"},
|
||||
{name = "lamp", mts = schem_path.."lamp.mts", hwidth = 3, hdepth = 3, hheight = 13, hsize = 10, max_num = 0.1, rplc = "n"},
|
||||
{name = "library", mts = schem_path.."library.mts", hwidth = 12, hdepth = 12, hheight = 8, hsize = 13, max_num = 0.04, rplc = "n"},
|
||||
{name = "medium_house", mts = schem_path.."medium_house.mts", hwidth = 8, hdepth = 12, hheight = 8, hsize = 14, max_num = 0.09, rplc = "n"},
|
||||
{name = "small_house", mts = schem_path.."small_house.mts", hwidth = 9, hdepth = 7, hheight = 8, hsize = 13, max_num = 0.7, rplc = "n"},
|
||||
{name = "tavern", mts = schem_path.."tavern.mts", hwidth = 11, hdepth = 10, hheight = 10, hsize = 13, max_num = 0.050, rplc = "n"},
|
||||
{name = "well", mts = schem_path.."well.mts", hwidth = 6, hdepth = 8, hheight = 6, hsize = 10, max_num = 0.045, rplc = "n"},
|
||||
}
|
||||
--
|
||||
-- list of settlements, load on server start up
|
||||
--
|
||||
settlements_in_world = {}
|
||||
--
|
||||
-- min_distance between settlements
|
||||
--
|
||||
settlements.min_dist_settlements = 64
|
||||
--
|
||||
-- maximum allowed difference in height for building a sttlement
|
||||
--
|
||||
max_height_difference = 56
|
||||
--
|
||||
--
|
||||
--
|
||||
half_map_chunk_size = 40
|
||||
quarter_map_chunk_size = 20
|
|
@ -0,0 +1,30 @@
|
|||
--
|
||||
function settlements.convert_mts_to_lua()
|
||||
local building = schem_path.."townhall.mts"
|
||||
local str = minetest.serialize_schematic(building, "lua", {lua_use_comments = true, lua_num_indent_spaces = 0}).." return(schematic)"
|
||||
local schematic = loadstring(str)()
|
||||
local file = io.open(schem_path.."church"..".lua", "w")
|
||||
file:write(dump(schematic))
|
||||
file:close()
|
||||
print(dump(schematic))
|
||||
end
|
||||
|
||||
|
||||
|
||||
function settlements.mts_save()
|
||||
local f = assert(io.open(schem_path.."hut.lua", "r"))
|
||||
local content = f:read("*all").." return(schematic2)"
|
||||
f:close()
|
||||
|
||||
local schematic2 = loadstring("schematic2 = "..content)()
|
||||
local seb = minetest.serialize_schematic(schematic2, "mts", {})
|
||||
local filename = schem_path .. "hut2" .. ".mts"
|
||||
filename = filename:gsub("\"", "\\\""):gsub("\\", "\\\\")
|
||||
local file, err = io.open(filename, "wb")
|
||||
if err == nil and seb then
|
||||
file:write(seb)
|
||||
file:flush()
|
||||
file:close()
|
||||
end
|
||||
print("Wrote: " .. filename)
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
mcl_core
|
||||
mcl_farming?
|
||||
mobs_mc?
|
|
@ -0,0 +1,153 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- function to fill empty space below baseplate when building on a hill
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.ground_lvm(pos, pr) -- role model: Wendelsteinkircherl, Brannenburg
|
||||
local c_dirt = minetest.get_content_id("mcl_core:dirt")
|
||||
local c_stone = minetest.get_content_id("mcl_core:stone")
|
||||
--
|
||||
local p2 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local mat = c_dirt
|
||||
p2.y = p2.y-1
|
||||
while true do
|
||||
cnt = cnt+1
|
||||
if cnt > 20 then break end
|
||||
if cnt>pr:next(2,4) then mat = c_stone end
|
||||
--minetest.swap_node(p2, {name="mcl_core:"..mat})
|
||||
local vi = va:index(p2.x, p2.y, p2.z)
|
||||
data[vi] = mat
|
||||
p2.y = p2.y-1
|
||||
end
|
||||
-- return data
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to fill empty space below baseplate when building on a hill
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.ground(pos, pr) -- role model: Wendelsteinkircherl, Brannenburg
|
||||
local p2 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local mat = "mcl_core:dirt"
|
||||
p2.y = p2.y-1
|
||||
while true do
|
||||
cnt = cnt+1
|
||||
if cnt > 20 then break end
|
||||
if cnt>pr:next(2,4) then
|
||||
mat = "mcl_core:stone"
|
||||
end
|
||||
minetest.swap_node(p2, {name=mat})
|
||||
p2.y = p2.y-1
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function clear space above baseplate
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.terraform_lvm(settlement_info, pr)
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local fheight
|
||||
local fwidth
|
||||
local fdepth
|
||||
|
||||
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
-- pick right schematic_info to current built_house
|
||||
for j, schem in ipairs(schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"]
|
||||
then
|
||||
schematic_data = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
local pos = settlement_info[i]["pos"]
|
||||
if settlement_info[i]["rotat"] == "0" or settlement_info[i]["rotat"] == "180"
|
||||
then
|
||||
fwidth = schematic_data["hwidth"]
|
||||
fdepth = schematic_data["hdepth"]
|
||||
else
|
||||
fwidth = schematic_data["hdepth"]
|
||||
fdepth = schematic_data["hwidth"]
|
||||
end
|
||||
fheight = schematic_data["hheight"] * 3 -- remove trees and leaves above
|
||||
--
|
||||
-- now that every info is available -> create platform and clear space above
|
||||
--
|
||||
for zi = 0,fdepth-1 do
|
||||
for yi = 0,fheight do
|
||||
for xi = 0,fwidth-1 do
|
||||
if yi == 0 then
|
||||
local p = {x=pos.x+xi, y=pos.y, z=pos.z+zi}
|
||||
settlements.ground_lvm(p, pr)
|
||||
else
|
||||
--break --todo
|
||||
-- write ground
|
||||
local vi = va:index(pos.x+xi, pos.y+yi, pos.z+zi)
|
||||
if data[vi] ~= c_air
|
||||
--local node = minetest.get_node_or_nil({x=p5.x+xi, y=p5.y+yi, z=p5.z+zi})
|
||||
--if node then
|
||||
--if node.name ~= "air"
|
||||
then
|
||||
--minetest.swap_node({x=pos.x+xi, y=pos.y+yi, z=pos.z+zi},{name="air"})
|
||||
data[vi] = c_air
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function clear space above baseplate
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.terraform(settlement_info, pr)
|
||||
local fheight
|
||||
local fwidth
|
||||
local fdepth
|
||||
local schematic_data
|
||||
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
-- pick right schematic_info to current built_house
|
||||
for j, schem in ipairs(schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"]
|
||||
then
|
||||
schematic_data = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
local pos = settlement_info[i]["pos"]
|
||||
if settlement_info[i]["rotat"] == "0" or settlement_info[i]["rotat"] == "180"
|
||||
then
|
||||
fwidth = schematic_data["hwidth"]
|
||||
fdepth = schematic_data["hdepth"]
|
||||
else
|
||||
fwidth = schematic_data["hdepth"]
|
||||
fdepth = schematic_data["hwidth"]
|
||||
end
|
||||
--fheight = schematic_data["hheight"] * 3 -- remove trees and leaves above
|
||||
fheight = schematic_data["hheight"] -- remove trees and leaves above
|
||||
--
|
||||
-- now that every info is available -> create platform and clear space above
|
||||
--
|
||||
for xi = 0,fwidth-1 do
|
||||
for zi = 0,fdepth-1 do
|
||||
for yi = 0,fheight *3 do
|
||||
if yi == 0 then
|
||||
local p = {x=pos.x+xi, y=pos.y, z=pos.z+zi}
|
||||
settlements.ground(p, pr)
|
||||
else
|
||||
-- write ground
|
||||
local p = {x=pos.x+xi, y=pos.y+yi, z=pos.z+zi}
|
||||
minetest.forceload_block(p)
|
||||
local node = minetest.get_node_or_nil(p)
|
||||
if node then
|
||||
if node.name ~= "air"
|
||||
then
|
||||
minetest.swap_node(p,{name="air"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,235 @@
|
|||
-- eclipse debugging lines
|
||||
--require("debugger")(idehost, ideport, idekey)
|
||||
|
||||
--zerobrane debugging lines
|
||||
--package.cpath = package.cpath .. ";/usr/share/lua/5.2/?.so"
|
||||
--package.path = package.path .. ";/usr/share/zbstudio/lualibs/mobdebug/?.lua"
|
||||
--require('mobdebug').start()
|
||||
|
||||
settlements = {}
|
||||
settlements.modpath = minetest.get_modpath("mcl_villages");
|
||||
|
||||
dofile(settlements.modpath.."/const.lua")
|
||||
dofile(settlements.modpath.."/utils.lua")
|
||||
dofile(settlements.modpath.."/foundation.lua")
|
||||
dofile(settlements.modpath.."/buildings.lua")
|
||||
dofile(settlements.modpath.."/paths.lua")
|
||||
dofile(settlements.modpath.."/convert_lua_mts.lua")
|
||||
--
|
||||
-- load settlements on server
|
||||
--
|
||||
settlements_in_world = settlements.load()
|
||||
settlements.grundstellungen()
|
||||
|
||||
--[[ Disable custom node spawning.
|
||||
--
|
||||
-- register block for npc spawn
|
||||
--
|
||||
minetest.register_node("settlements:junglewood", {
|
||||
description = "special junglewood floor",
|
||||
tiles = {"default_junglewood.png"},
|
||||
groups = {choppy=3, wood=2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
--]]
|
||||
|
||||
|
||||
--[[ Enable for testing, but use MineClone2's own spawn code if/when merging.
|
||||
--
|
||||
-- register inhabitants
|
||||
--
|
||||
if minetest.get_modpath("mobs_mc") ~= nil then
|
||||
mobs:register_spawn("mobs_mc:villager", --name
|
||||
{"mcl_core:stonebrickcarved"}, --nodes
|
||||
15, --max_light
|
||||
0, --min_light
|
||||
20, --chance
|
||||
7, --active_object_count
|
||||
31000, --max_height
|
||||
nil) --day_toggle
|
||||
end
|
||||
--]]
|
||||
|
||||
--
|
||||
-- on map generation, try to build a settlement
|
||||
--
|
||||
local function build_a_settlement_no_delay(minp, maxp, blockseed)
|
||||
local settlement_info
|
||||
local pr = PseudoRandom(blockseed)
|
||||
--
|
||||
-- fill settlement_info with buildings and their data
|
||||
--
|
||||
if settlements.lvm == true then
|
||||
-- get LVM of current chunk
|
||||
local vm, data, va, emin, emax = settlements.getlvm(minp, maxp)
|
||||
settlement_info = settlements.create_site_plan_lvm(maxp, minp, pr)
|
||||
else
|
||||
settlement_info = settlements.create_site_plan(maxp, minp, pr)
|
||||
end
|
||||
if not settlement_info then return end
|
||||
|
||||
-- evaluate settlement_info and prepair terrain
|
||||
if settlements.lvm == true then
|
||||
settlements.terraform_lvm(settlement_info, pr)
|
||||
else
|
||||
settlements.terraform(settlement_info, pr)
|
||||
end
|
||||
|
||||
-- evaluate settlement_info and build paths between buildings
|
||||
if settlements.lvm == true then
|
||||
settlements.paths_lvm(settlement_info, minp)
|
||||
else
|
||||
settlements.paths(settlement_info)
|
||||
end
|
||||
|
||||
-- evaluate settlement_info and place schematics
|
||||
if settlements.lvm == true then
|
||||
vm:set_data(data)
|
||||
settlements.place_schematics_lvm(settlement_info, pr)
|
||||
vm:write_to_map(true)
|
||||
else
|
||||
settlements.place_schematics(settlement_info, pr)
|
||||
end
|
||||
|
||||
-- evaluate settlement_info and initialize furnaces and chests
|
||||
settlements.initialize_nodes(settlement_info, pr)
|
||||
end
|
||||
|
||||
local function ecb_build_a_settlement(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining <= 0 then
|
||||
build_a_settlement_no_delay(param.minp, param.maxp, param.blockseed)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed)
|
||||
-- needed for manual and automated settlement building
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
|
||||
-- randomly try to build settlements
|
||||
if blockseed % 77 ~= 17 then return end
|
||||
|
||||
-- don't build settlement underground
|
||||
if maxp.y < 0 then return end
|
||||
|
||||
-- don't build settlements too close to each other
|
||||
local center_of_chunk = {
|
||||
x=maxp.x-half_map_chunk_size,
|
||||
y=maxp.y-half_map_chunk_size,
|
||||
z=maxp.z-half_map_chunk_size
|
||||
}
|
||||
local dist_ok = settlements.check_distance_other_settlements(center_of_chunk)
|
||||
if dist_ok == false then return end
|
||||
|
||||
-- don't build settlements on (too) uneven terrain
|
||||
local height_difference = settlements.evaluate_heightmap(minp, maxp)
|
||||
if height_difference > max_height_difference then return end
|
||||
|
||||
minetest.emerge_area(vector.subtract(minp,24), vector.add(maxp,24), ecb_build_a_settlement, {minp = vector.new(minp), maxp=vector.new(maxp), blockseed=blockseed})
|
||||
-- old way - wait 3 seconds:
|
||||
-- minetest.after(3, ecb_build_a_settlement, nil, 1, 0, {minp = vector.new(minp), maxp=vector.new(maxp), blockseed=blockseed})
|
||||
end)
|
||||
|
||||
--
|
||||
-- manually place buildings, for debugging only
|
||||
--
|
||||
minetest.register_craftitem("mcl_villages:tool", {
|
||||
description = "mcl_villages build tool",
|
||||
inventory_image = "default_tool_woodshovel.png",
|
||||
|
||||
--[[ Disable on_use for now.
|
||||
-- build single house
|
||||
--
|
||||
on_use = function(itemstack, placer, pointed_thing)
|
||||
local center_surface = pointed_thing.under
|
||||
if center_surface then
|
||||
local building_all_info = {name = "blacksmith",
|
||||
mts = schem_path.."blacksmith.mts",
|
||||
hsize = 13,
|
||||
max_num = 0.9,
|
||||
rplc = "n"}
|
||||
settlements.build_schematic(center_surface,
|
||||
building_all_info["mts"],
|
||||
building_all_info["rplc"],
|
||||
building_all_info["name"])
|
||||
|
||||
-- settlements.convert_mts_to_lua()
|
||||
-- settlements.mts_save()
|
||||
end
|
||||
end,
|
||||
--]]
|
||||
--
|
||||
-- build ssettlement
|
||||
--
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local pr = PseudoRandom(math.rand(0,32767))
|
||||
-- enable debug routines
|
||||
local center_surface = pointed_thing.under
|
||||
if center_surface then
|
||||
local minp = {
|
||||
x=center_surface.x-half_map_chunk_size,
|
||||
y=center_surface.y-half_map_chunk_size,
|
||||
z=center_surface.z-half_map_chunk_size
|
||||
}
|
||||
local maxp = {
|
||||
x=center_surface.x+half_map_chunk_size,
|
||||
y=center_surface.y+half_map_chunk_size,
|
||||
z=center_surface.z+half_map_chunk_size
|
||||
}
|
||||
--
|
||||
-- get LVM of current chunk
|
||||
--
|
||||
local vm, data, va, emin, emax = settlements.getlvm(minp, maxp)
|
||||
--
|
||||
-- fill settlement_info with buildings and their data
|
||||
--
|
||||
local start_time = os.time()
|
||||
local settlement_info
|
||||
if settlements.lvm == true then
|
||||
settlement_info = settlements.create_site_plan_lvm(maxp, minp, pr)
|
||||
else
|
||||
settlement_info = settlements.create_site_plan(maxp, minp, pr)
|
||||
end
|
||||
if not settlement_info then return end
|
||||
--
|
||||
-- evaluate settlement_info and prepair terrain
|
||||
--
|
||||
if settlements.lvm == true then
|
||||
settlements.terraform_lvm(settlement_info, pr)
|
||||
else
|
||||
settlements.terraform(settlement_info, pr)
|
||||
end
|
||||
|
||||
--
|
||||
-- evaluate settlement_info and build paths between buildings
|
||||
--
|
||||
if settlements.lvm == true then
|
||||
settlements.paths_lvm(settlement_info, minp)
|
||||
else
|
||||
settlements.paths(settlement_info)
|
||||
end
|
||||
--
|
||||
-- evaluate settlement_info and place schematics
|
||||
--
|
||||
if settlements.lvm == true then
|
||||
vm:set_data(data)
|
||||
settlements.place_schematics_lvm(pr)
|
||||
vm:write_to_map(true)
|
||||
else
|
||||
settlements.place_schematics()
|
||||
end
|
||||
|
||||
--
|
||||
-- evaluate settlement_info and initialize furnaces and chests
|
||||
--
|
||||
settlements.initialize_nodes(settlement_info, pr)
|
||||
local end_time = os.time()
|
||||
minetest.chat_send_all("Time ".. end_time - start_time)
|
||||
--
|
||||
--settlements.convert_mts_to_lua()
|
||||
--settlements.mts_save()
|
||||
|
||||
end
|
||||
end
|
||||
})
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- generate paths between buildings
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.paths_lvm(settlement_info, minp)
|
||||
local c_grasspath = minetest.get_content_id("mcl_core:grass_path")
|
||||
local starting_point
|
||||
local end_point
|
||||
local distance
|
||||
--for k,v in pairs(settlement_info) do
|
||||
starting_point = settlement_info[1]["pos"]
|
||||
for o,p in pairs(settlement_info) do
|
||||
|
||||
end_point = settlement_info[o]["pos"]
|
||||
if starting_point ~= end_point
|
||||
then
|
||||
-- loop until end_point is reched (distance == 0)
|
||||
while true do
|
||||
|
||||
-- define surrounding pos to starting_point
|
||||
local north_p = {x=starting_point.x+1, y=starting_point.y, z=starting_point.z}
|
||||
local south_p = {x=starting_point.x-1, y=starting_point.y, z=starting_point.z}
|
||||
local west_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z+1}
|
||||
local east_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z-1}
|
||||
-- measure distance to end_point
|
||||
local dist_north_p_to_end = math.sqrt(
|
||||
((north_p.x - end_point.x)*(north_p.x - end_point.x))+
|
||||
((north_p.z - end_point.z)*(north_p.z - end_point.z))
|
||||
)
|
||||
local dist_south_p_to_end = math.sqrt(
|
||||
((south_p.x - end_point.x)*(south_p.x - end_point.x))+
|
||||
((south_p.z - end_point.z)*(south_p.z - end_point.z))
|
||||
)
|
||||
local dist_west_p_to_end = math.sqrt(
|
||||
((west_p.x - end_point.x)*(west_p.x - end_point.x))+
|
||||
((west_p.z - end_point.z)*(west_p.z - end_point.z))
|
||||
)
|
||||
local dist_east_p_to_end = math.sqrt(
|
||||
((east_p.x - end_point.x)*(east_p.x - end_point.x))+
|
||||
((east_p.z - end_point.z)*(east_p.z - end_point.z))
|
||||
)
|
||||
-- evaluate which pos is closer to the end_point
|
||||
if dist_north_p_to_end <= dist_south_p_to_end and
|
||||
dist_north_p_to_end <= dist_west_p_to_end and
|
||||
dist_north_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = north_p
|
||||
distance = dist_north_p_to_end
|
||||
|
||||
elseif dist_south_p_to_end <= dist_north_p_to_end and
|
||||
dist_south_p_to_end <= dist_west_p_to_end and
|
||||
dist_south_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = south_p
|
||||
distance = dist_south_p_to_end
|
||||
|
||||
elseif dist_west_p_to_end <= dist_north_p_to_end and
|
||||
dist_west_p_to_end <= dist_south_p_to_end and
|
||||
dist_west_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = west_p
|
||||
distance = dist_west_p_to_end
|
||||
|
||||
elseif dist_east_p_to_end <= dist_north_p_to_end and
|
||||
dist_east_p_to_end <= dist_south_p_to_end and
|
||||
dist_east_p_to_end <= dist_west_p_to_end
|
||||
then
|
||||
starting_point = east_p
|
||||
distance = dist_east_p_to_end
|
||||
end
|
||||
-- find surface of new starting point
|
||||
local surface_point, surface_mat = settlements.find_surface_lvm(starting_point, minp)
|
||||
-- replace surface node with mcl_core:grass_path
|
||||
if surface_point
|
||||
then
|
||||
local vi = va:index(surface_point.x, surface_point.y, surface_point.z)
|
||||
data[vi] = c_grasspath
|
||||
|
||||
--minetest.swap_node(surface_point,{name="mcl_core:grass_path"})
|
||||
-- don't set y coordinate, surface might be too low or high
|
||||
starting_point.x = surface_point.x
|
||||
starting_point.z = surface_point.z
|
||||
end
|
||||
if distance <= 1 or
|
||||
starting_point == end_point
|
||||
then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--end
|
||||
--return data
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- generate paths between buildings
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.paths(settlement_info)
|
||||
local starting_point
|
||||
local end_point
|
||||
local distance
|
||||
--for k,v in pairs(settlement_info) do
|
||||
starting_point = settlement_info[1]["pos"]
|
||||
for o,p in pairs(settlement_info) do
|
||||
|
||||
end_point = settlement_info[o]["pos"]
|
||||
if starting_point ~= end_point
|
||||
then
|
||||
-- loop until end_point is reched (distance == 0)
|
||||
while true do
|
||||
|
||||
-- define surrounding pos to starting_point
|
||||
local north_p = {x=starting_point.x+1, y=starting_point.y, z=starting_point.z}
|
||||
local south_p = {x=starting_point.x-1, y=starting_point.y, z=starting_point.z}
|
||||
local west_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z+1}
|
||||
local east_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z-1}
|
||||
-- measure distance to end_point
|
||||
local dist_north_p_to_end = math.sqrt(
|
||||
((north_p.x - end_point.x)*(north_p.x - end_point.x))+
|
||||
((north_p.z - end_point.z)*(north_p.z - end_point.z))
|
||||
)
|
||||
local dist_south_p_to_end = math.sqrt(
|
||||
((south_p.x - end_point.x)*(south_p.x - end_point.x))+
|
||||
((south_p.z - end_point.z)*(south_p.z - end_point.z))
|
||||
)
|
||||
local dist_west_p_to_end = math.sqrt(
|
||||
((west_p.x - end_point.x)*(west_p.x - end_point.x))+
|
||||
((west_p.z - end_point.z)*(west_p.z - end_point.z))
|
||||
)
|
||||
local dist_east_p_to_end = math.sqrt(
|
||||
((east_p.x - end_point.x)*(east_p.x - end_point.x))+
|
||||
((east_p.z - end_point.z)*(east_p.z - end_point.z))
|
||||
)
|
||||
-- evaluate which pos is closer to the end_point
|
||||
if dist_north_p_to_end <= dist_south_p_to_end and
|
||||
dist_north_p_to_end <= dist_west_p_to_end and
|
||||
dist_north_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = north_p
|
||||
distance = dist_north_p_to_end
|
||||
|
||||
elseif dist_south_p_to_end <= dist_north_p_to_end and
|
||||
dist_south_p_to_end <= dist_west_p_to_end and
|
||||
dist_south_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = south_p
|
||||
distance = dist_south_p_to_end
|
||||
|
||||
elseif dist_west_p_to_end <= dist_north_p_to_end and
|
||||
dist_west_p_to_end <= dist_south_p_to_end and
|
||||
dist_west_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = west_p
|
||||
distance = dist_west_p_to_end
|
||||
|
||||
elseif dist_east_p_to_end <= dist_north_p_to_end and
|
||||
dist_east_p_to_end <= dist_south_p_to_end and
|
||||
dist_east_p_to_end <= dist_west_p_to_end
|
||||
then
|
||||
starting_point = east_p
|
||||
distance = dist_east_p_to_end
|
||||
end
|
||||
-- find surface of new starting point
|
||||
local surface_point, surface_mat = settlements.find_surface(starting_point)
|
||||
-- replace surface node with mcl_core:grass_path
|
||||
if surface_point
|
||||
then
|
||||
minetest.swap_node(surface_point,{name="mcl_core:grass_path"})
|
||||
-- don't set y coordinate, surface might be too low or high
|
||||
starting_point.x = surface_point.x
|
||||
starting_point.z = surface_point.z
|
||||
end
|
||||
if distance <= 1 or
|
||||
starting_point == end_point
|
||||
then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
|
@ -0,0 +1,424 @@
|
|||
local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass")
|
||||
local c_dirt_with_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow")
|
||||
--local c_dirt_with_dry_grass = minetest.get_content_id("mcl_core:dirt_with_dry_grass")
|
||||
local c_podzol = minetest.get_content_id("mcl_core:podzol")
|
||||
local c_sand = minetest.get_content_id("mcl_core:sand")
|
||||
local c_desert_sand = minetest.get_content_id("mcl_core:redsand")
|
||||
--local c_silver_sand = minetest.get_content_id("mcl_core:silver_sand")
|
||||
--
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local c_snow = minetest.get_content_id("mcl_core:snowblock")
|
||||
local c_fern_1 = minetest.get_content_id("mcl_flowers:fern")
|
||||
local c_fern_2 = minetest.get_content_id("mcl_flowers:fern")
|
||||
local c_fern_3 = minetest.get_content_id("mcl_flowers:fern")
|
||||
local c_rose = minetest.get_content_id("mcl_flowers:poppy")
|
||||
local c_viola = minetest.get_content_id("mcl_flowers:blue_orchid")
|
||||
local c_geranium = minetest.get_content_id("mcl_flowers:allium")
|
||||
local c_tulip = minetest.get_content_id("mcl_flowers:tulip_orange")
|
||||
local c_dandelion_y = minetest.get_content_id("mcl_flowers:dandelion")
|
||||
local c_dandelion_w = minetest.get_content_id("mcl_flowers:oxeye_daisy")
|
||||
local c_bush_leaves = minetest.get_content_id("mcl_core:leaves")
|
||||
local c_bush_stem = minetest.get_content_id("mcl_core:tree")
|
||||
local c_a_bush_leaves = minetest.get_content_id("mcl_core:acacialeaves")
|
||||
local c_a_bush_stem = minetest.get_content_id("mcl_core:acaciatree")
|
||||
local c_water_source = minetest.get_content_id("mcl_core:water_source")
|
||||
local c_water_flowing = minetest.get_content_id("mcl_core:water_flowing")
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to copy tables
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.shallowCopy(original)
|
||||
local copy = {}
|
||||
for key, value in pairs(original) do
|
||||
copy[key] = value
|
||||
end
|
||||
return copy
|
||||
end
|
||||
--
|
||||
--
|
||||
--
|
||||
function settlements.round(num, numDecimalPlaces)
|
||||
local mult = 10^(numDecimalPlaces or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to find surface block y coordinate
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.find_surface_lvm(pos, minp)
|
||||
--ab hier altes verfahren
|
||||
local p6 = vector.new(pos)
|
||||
local surface_mat = {
|
||||
c_dirt_with_grass,
|
||||
c_dirt_with_snow,
|
||||
--c_dirt_with_dry_grass,
|
||||
c_podzol,
|
||||
c_sand,
|
||||
c_desert_sand
|
||||
}
|
||||
local cnt = 0
|
||||
local itter -- count up or down
|
||||
local cnt_max = 200
|
||||
-- starting point for looking for surface
|
||||
local vi = va:index(p6.x, p6.y, p6.z)
|
||||
if data[vi] == nil then return nil end
|
||||
local tmp = minetest.get_name_from_content_id(data[vi])
|
||||
if data[vi] == c_air then
|
||||
itter = -1
|
||||
else
|
||||
itter = 1
|
||||
end
|
||||
while cnt < cnt_max do
|
||||
cnt = cnt+1
|
||||
local vi = va:index(p6.x, p6.y, p6.z)
|
||||
-- local tmp = minetest.get_name_from_content_id(data[vi])
|
||||
-- if vi == nil
|
||||
-- then
|
||||
-- return nil
|
||||
-- end
|
||||
for i, mats in ipairs(surface_mat) do
|
||||
local node_check = va:index(p6.x, p6.y+1, p6.z)
|
||||
if node_check and vi and data[vi] == mats and
|
||||
(data[node_check] ~= c_water_source and
|
||||
data[node_check] ~= c_water_flowing
|
||||
)
|
||||
then
|
||||
local tmp = minetest.get_name_from_content_id(data[node_check])
|
||||
return p6, mats
|
||||
end
|
||||
end
|
||||
p6.y = p6.y + itter
|
||||
if p6.y < 0 then return nil end
|
||||
end
|
||||
return nil --]]
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to find surface block y coordinate
|
||||
-- returns surface postion
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.find_surface(pos)
|
||||
local p6 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local itter -- count up or down
|
||||
local cnt_max = 200
|
||||
-- check, in which direction to look for surface
|
||||
local surface_node = minetest.get_node_or_nil(p6)
|
||||
if surface_node and string.find(surface_node.name,"air") then
|
||||
itter = -1
|
||||
else
|
||||
itter = 1
|
||||
end
|
||||
-- go through nodes an find surface
|
||||
while cnt < cnt_max do
|
||||
cnt = cnt+1
|
||||
minetest.forceload_block(p6)
|
||||
surface_node = minetest.get_node_or_nil(p6)
|
||||
|
||||
if not surface_node then
|
||||
-- Load the map at pos and try again
|
||||
minetest.get_voxel_manip():read_from_map(p6, p6)
|
||||
surface_node = minetest.get_node(p6)
|
||||
if surface_node.name == "ignore" then
|
||||
settlements.debug("find_surface1: nil or ignore")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- if surface_node == nil or surface_node.name == "ignore" then
|
||||
-- --return nil
|
||||
-- local fl = minetest.forceload_block(p6)
|
||||
-- if not fl then
|
||||
--
|
||||
-- return nil
|
||||
-- end
|
||||
-- end
|
||||
--
|
||||
-- Check Surface_node and Node above
|
||||
--
|
||||
if settlements.surface_mat[surface_node.name] then
|
||||
local surface_node_plus_1 = minetest.get_node_or_nil({ x=p6.x, y=p6.y+1, z=p6.z})
|
||||
if surface_node_plus_1 and surface_node and
|
||||
(string.find(surface_node_plus_1.name,"air") or
|
||||
string.find(surface_node_plus_1.name,"snow") or
|
||||
string.find(surface_node_plus_1.name,"fern") or
|
||||
string.find(surface_node_plus_1.name,"flower") or
|
||||
string.find(surface_node_plus_1.name,"bush") or
|
||||
string.find(surface_node_plus_1.name,"tree") or
|
||||
string.find(surface_node_plus_1.name,"grass"))
|
||||
then
|
||||
settlements.debug("find_surface7: " ..surface_node.name.. " " .. surface_node_plus_1.name)
|
||||
return p6, surface_node.name
|
||||
else
|
||||
settlements.debug("find_surface2: wrong surface+1")
|
||||
end
|
||||
else
|
||||
settlements.debug("find_surface3: wrong surface "..surface_node.name.." at pos "..minetest.pos_to_string(p6))
|
||||
end
|
||||
|
||||
p6.y = p6.y + itter
|
||||
if p6.y < 0 then
|
||||
settlements.debug("find_surface4: y<0")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
settlements.debug("find_surface5: cnt_max overflow")
|
||||
return nil
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- check distance for new building
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.check_distance(settlement_info, building_pos, building_size)
|
||||
local distance
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
distance = math.sqrt(
|
||||
((building_pos.x - built_house["pos"].x)*(building_pos.x - built_house["pos"].x))+
|
||||
((building_pos.z - built_house["pos"].z)*(building_pos.z - built_house["pos"].z)))
|
||||
if distance < building_size or
|
||||
distance < built_house["hsize"]
|
||||
then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- save list of generated settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.save()
|
||||
local file = io.open(minetest.get_worldpath().."/settlements.txt", "w")
|
||||
if file then
|
||||
file:write(minetest.serialize(settlements_in_world))
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- load list of generated settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.load()
|
||||
local file = io.open(minetest.get_worldpath().."/settlements.txt", "r")
|
||||
if file then
|
||||
local table = minetest.deserialize(file:read("*all"))
|
||||
if type(table) == "table" then
|
||||
return table
|
||||
end
|
||||
end
|
||||
return {}
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- check distance to other settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.check_distance_other_settlements(center_new_chunk)
|
||||
-- local min_dist_settlements = 300
|
||||
for i, pos in ipairs(settlements_in_world) do
|
||||
local distance = vector.distance(center_new_chunk, pos)
|
||||
-- minetest.chat_send_all("dist ".. distance)
|
||||
if distance < settlements.min_dist_settlements then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- fill chests
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.fill_chest(pos, pr)
|
||||
-- find chests within radius
|
||||
--local chestpos = minetest.find_node_near(pos, 6, {"mcl_core:chest"})
|
||||
local chestpos = pos
|
||||
-- initialize chest (mts chests don't have meta)
|
||||
local meta = minetest.get_meta(chestpos)
|
||||
if meta:get_string("infotext") ~= "Chest" then
|
||||
-- For MineClone2 0.70 or before
|
||||
-- minetest.registered_nodes["mcl_chests:chest"].on_construct(chestpos)
|
||||
--
|
||||
-- For MineClone2 after commit 09ab1482b5 (the new entity chests)
|
||||
minetest.registered_nodes["mcl_chests:chest_small"].on_construct(chestpos)
|
||||
end
|
||||
-- fill chest
|
||||
local inv = minetest.get_inventory( {type="node", pos=chestpos} )
|
||||
-- always
|
||||
inv:add_item("main", "mcl_core:apple "..pr:next(1,3))
|
||||
-- low value items
|
||||
if pr:next(0,1) < 1 then
|
||||
inv:add_item("main", "mcl_farming:bread "..pr:next(0,3))
|
||||
inv:add_item("main", "mcl_core:iron_ingot "..pr:next(0,3))
|
||||
inv:add_item("main", "mcl_farming:melon_item "..pr:next(0,3))
|
||||
inv:add_item("main", "mcl_farming:carrot_item "..pr:next(0,3))
|
||||
--[[
|
||||
-- additional fillings when farmin mod enabled
|
||||
if minetest.get_modpath("farming") ~= nil and farming.mod == "redo" then
|
||||
if pr:next(0,1) < 1 then
|
||||
inv:add_item("main", "mcl_farming:melon_item "..pr:next(0,3))
|
||||
inv:add_item("main", "mcl_farming:carrot_item "..pr:next(0,3))
|
||||
inv:add_item("main", "farming:corn "..pr:next(0,3))
|
||||
end
|
||||
end
|
||||
--]]
|
||||
end
|
||||
-- medium value items
|
||||
if pr:next(0,3) < 1 then
|
||||
inv:add_item("main", "mcl_tools:pick_iron "..pr:next(0,1))
|
||||
inv:add_item("main", "mcl_tools:pick_stone "..pr:next(0,1))
|
||||
inv:add_item("main", "mcl_fire:flint_and_steel "..pr:next(0,1))
|
||||
inv:add_item("main", "mcl_buckets:bucket_empty "..pr:next(0,1))
|
||||
inv:add_item("main", "mcl_tools:sword_iron "..pr:next(0,1))
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize furnace
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_furnace(pos)
|
||||
-- find chests within radius
|
||||
local furnacepos = minetest.find_node_near(pos,
|
||||
7, --radius
|
||||
{"mcl_furnaces:furnace"})
|
||||
-- initialize furnacepos (mts furnacepos don't have meta)
|
||||
if furnacepos
|
||||
then
|
||||
local meta = minetest.get_meta(furnacepos)
|
||||
if meta:get_string("infotext") ~= "furnace"
|
||||
then
|
||||
minetest.registered_nodes["mcl_furnaces:furnace"].on_construct(furnacepos)
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize anvil
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_anvil(pos)
|
||||
-- find chests within radius
|
||||
local anvilpos = minetest.find_node_near(pos,
|
||||
7, --radius
|
||||
{"mcl_anvils:anvil"})
|
||||
-- initialize anvilpos (mts anvilpos don't have meta)
|
||||
if anvilpos
|
||||
then
|
||||
local meta = minetest.get_meta(anvilpos)
|
||||
if meta:get_string("infotext") ~= "anvil"
|
||||
then
|
||||
minetest.registered_nodes["mcl_anvils:anvil"].on_construct(anvilpos)
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize furnace, chests, anvil
|
||||
-------------------------------------------------------------------------------
|
||||
local building_all_info
|
||||
function settlements.initialize_nodes(settlement_info, pr)
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
for j, schem in ipairs(schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
building_all_info = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local width = building_all_info["hwidth"]
|
||||
local depth = building_all_info["hdepth"]
|
||||
local height = building_all_info["hheight"]
|
||||
|
||||
local p = settlement_info[i]["pos"]
|
||||
for yi = 1,height do
|
||||
for xi = 0,width do
|
||||
for zi = 0,depth do
|
||||
local ptemp = {x=p.x+xi, y=p.y+yi, z=p.z+zi}
|
||||
local node = minetest.get_node(ptemp)
|
||||
if node.name == "mcl_furnaces:furnace" or
|
||||
node.name == "mcl_chests:chest" or
|
||||
node.name == "mcl_anvils:anvil" then
|
||||
minetest.registered_nodes[node.name].on_construct(ptemp)
|
||||
end
|
||||
-- when chest is found -> fill with stuff
|
||||
if node.name == "mcl_chests:chest" then
|
||||
minetest.after(3, settlements.fill_chest, ptemp, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- randomize table
|
||||
-------------------------------------------------------------------------------
|
||||
function shuffle(tbl, pr)
|
||||
local table = settlements.shallowCopy(tbl)
|
||||
local size = #table
|
||||
for i = size, 1, -1 do
|
||||
local rand = pr:next(1, size)
|
||||
table[i], table[rand] = table[rand], table[i]
|
||||
end
|
||||
return table
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate heightmap
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.evaluate_heightmap()
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
-- max height and min height, initialize with impossible values for easier first time setting
|
||||
local max_y = -50000
|
||||
local min_y = 50000
|
||||
-- only evaluate the center square of heightmap 40 x 40
|
||||
local square_start = 1621
|
||||
local square_end = 1661
|
||||
for j = 1 , 40, 1 do
|
||||
for i = square_start, square_end, 1 do
|
||||
-- skip buggy heightmaps, return high value
|
||||
if heightmap[i] == -31000 or
|
||||
heightmap[i] == 31000
|
||||
then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
if heightmap[i] < min_y
|
||||
then
|
||||
min_y = heightmap[i]
|
||||
end
|
||||
if heightmap[i] > max_y
|
||||
then
|
||||
max_y = heightmap[i]
|
||||
end
|
||||
end
|
||||
-- set next line
|
||||
square_start = square_start + 80
|
||||
square_end = square_end + 80
|
||||
end
|
||||
-- return the difference between highest and lowest pos in chunk
|
||||
local height_diff = max_y - min_y
|
||||
-- filter buggy heightmaps
|
||||
if height_diff <= 1
|
||||
then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
-- debug info
|
||||
settlements.debug("heightdiff ".. height_diff)
|
||||
return height_diff
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- get LVM of current chunk
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.getlvm(minp, maxp)
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map(minp, maxp)
|
||||
local va = VoxelArea:new{
|
||||
MinEdge = emin,
|
||||
MaxEdge = emax
|
||||
}
|
||||
local data = vm:get_data()
|
||||
return vm, data, va, emin, emax
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- get LVM of current chunk
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.setlvm(vm, data)
|
||||
-- Write data
|
||||
vm:set_data(data)
|
||||
vm:write_to_map(true)
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.Set (list)
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
end
|
Loading…
Reference in New Issue