forked from VoxeLibre/VoxeLibre
425 lines
15 KiB
Lua
425 lines
15 KiB
Lua
|
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
|