141 lines
5.1 KiB
Lua
141 lines
5.1 KiB
Lua
settlements = {}
|
|
|
|
local modname = minetest.get_current_modname()
|
|
local modpath = minetest.get_modpath(modname)
|
|
|
|
settlements.S = minetest.get_translator(modname)
|
|
|
|
settlements.half_map_chunk_size = tonumber(minetest.get_mapgen_setting("chunksize")) * 16 / 2
|
|
|
|
settlements.surface_materials = {}
|
|
settlements.registered_settlements = {}
|
|
|
|
-- Minimum distance between settlements
|
|
settlements.min_dist_settlements = tonumber(minetest.settings:get("settlements_minimum_distance_between_settlements")) or 500
|
|
-- maximum allowed difference in height for building a settlement
|
|
local max_height_difference = tonumber(minetest.settings:get("settlements_maximum_height_difference")) or 10
|
|
|
|
dofile(modpath.."/upgrades.lua")
|
|
dofile(modpath.."/buildings.lua")
|
|
dofile(modpath.."/bookgen.lua")
|
|
dofile(modpath.."/admin_commands.lua")
|
|
dofile(modpath.."/admin_tools.lua")
|
|
|
|
settlements.register_settlement = function(settlement_type_name, settlement_def)
|
|
assert(not settlements.registered_settlements[settlement_type_name])
|
|
settlement_def.name = settlement_type_name
|
|
settlements.registered_settlements[settlement_type_name] = settlement_def
|
|
for _, material in ipairs(settlement_def.surface_materials) do
|
|
local c_mat = minetest.get_content_id(material)
|
|
local material_list = settlements.surface_materials[c_mat] or {}
|
|
settlements.surface_materials[c_mat] = material_list
|
|
table.insert(material_list, settlement_def)
|
|
end
|
|
end
|
|
|
|
-- Interconverting lua and mts formatted schematics
|
|
-- Useful for modders adding existing schematics that are in mts format
|
|
function settlements.convert_mts_to_lua(schem_path)
|
|
local str = minetest.serialize_schematic(schem_path, "lua", {lua_use_comments = true})
|
|
local file = io.open(schem_path:sub(1,-4).."lua", "w")
|
|
file:write(str.."\nreturn schematic")
|
|
file:close()
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- check distance to other settlements
|
|
-------------------------------------------------------------------------------
|
|
local function check_distance_other_settlements(center_new_chunk)
|
|
local min_edge = vector.subtract(center_new_chunk, settlements.min_dist_settlements)
|
|
local max_edge = vector.add(center_new_chunk, settlements.min_dist_settlements)
|
|
|
|
-- This gets all neighbors within a cube-shaped volume
|
|
local neighbors = named_waypoints.get_waypoints_in_area("settlements", min_edge, max_edge)
|
|
|
|
-- Search through those to find any that are within a spherical volume
|
|
for i, settlement in pairs(neighbors) do
|
|
local distance = vector.distance(center_new_chunk, settlement.pos)
|
|
if distance < settlements.min_dist_settlements then
|
|
return false
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- evaluate heightmap
|
|
-------------------------------------------------------------------------------
|
|
local function evaluate_heightmap(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 do
|
|
for i = square_start, square_end 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 < 0 then
|
|
return max_height_difference + 1
|
|
end
|
|
return height_diff
|
|
end
|
|
|
|
local half_map_chunk_size = settlements.half_map_chunk_size
|
|
|
|
minetest.register_on_generated(function(minp, maxp)
|
|
-- don't build settlement underground
|
|
if maxp.y < -100 then
|
|
return
|
|
end
|
|
|
|
local existing_settlements = named_waypoints.get_waypoints_in_area("settlements", minp, maxp)
|
|
local id, data = next(existing_settlements)
|
|
if id ~= nil then
|
|
-- There's already a settlement in this chunk despite us being in mapgen.
|
|
-- This chunk must have been previously generated and is now being re-generated. Override
|
|
-- any further checks and try building a settlement here.
|
|
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
|
local va = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
|
|
data = data.data
|
|
settlements.generate_settlement_vm(vm, va, minp, maxp, data.name)
|
|
return
|
|
end
|
|
|
|
-- don't build settlements too close to each other
|
|
local center_of_chunk = vector.subtract(maxp, half_map_chunk_size)
|
|
local dist_ok = check_distance_other_settlements(center_of_chunk)
|
|
if dist_ok == false then
|
|
return
|
|
end
|
|
|
|
-- don't build settlements on (too) uneven terrain
|
|
local heightmap = minetest.get_mapgen_object("heightmap")
|
|
local height_difference = evaluate_heightmap(heightmap)
|
|
if height_difference > max_height_difference then
|
|
return
|
|
end
|
|
|
|
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
|
local va = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
|
|
|
|
settlements.generate_settlement_vm(vm, va, minp, maxp)
|
|
end) |