VoxeLibre/mods/MAPGEN/mcl_villages/utils.lua

241 lines
8.6 KiB
Lua
Raw Normal View History

2024-07-19 14:56:06 +02:00
local function is_above_surface(name)
2024-07-26 01:13:21 +02:00
-- TODO: use groups
2024-07-19 14:56:06 +02:00
return name == "air" or
2024-07-24 17:29:40 +02:00
-- note: not dirt_with_grass!
2024-07-19 14:56:06 +02:00
string.find(name,"tree") or
string.find(name,"leaves") or
string.find(name,"snow") or
string.find(name,"fern") or
2024-07-24 17:29:40 +02:00
string.find(name,"flower") or -- includes grass decorations
2024-07-26 01:13:21 +02:00
string.find(name,"bush") or
name == "mcl_bamboo:bamboo" or name == "mcl_core:vine"
2024-07-19 14:56:06 +02:00
end
2024-07-23 01:09:17 +02:00
function mcl_villages.find_surface_down(lvm, pos, surface_node)
2024-07-19 14:56:06 +02:00
local p6 = vector.new(pos)
2024-07-23 01:09:17 +02:00
surface_node = surface_node or lvm:get_node_at(p6)
2024-07-19 14:56:06 +02:00
if not surface_node then return end
2024-07-24 17:29:40 +02:00
local has_air = is_above_surface(surface_node.name)
for y = p6.y - 1, math.max(0,p6.y - 80), -1 do
2024-07-19 14:56:06 +02:00
p6.y = y
local top_node = surface_node
2024-07-23 01:09:17 +02:00
surface_node = lvm:get_node_at(p6)
2024-07-24 17:29:40 +02:00
if not surface_node or surface_node.name == "ignore" then return nil end
if is_above_surface(surface_node.name) then
has_air = true
2024-07-19 14:56:06 +02:00
else
2024-07-24 17:29:40 +02:00
if has_air then
if mcl_villages.surface_mat[surface_node.name] then
--minetest.log("Found "..surface_node.name.." below "..top_node.name)
return p6, surface_node
else
local ndef = minetest.registered_nodes[surface_node.name]
if ndef and ndef.walkable then
--minetest.log("Found non-suitable "..surface_node.name.." below "..top_node.name)
return nil
end
end
2024-07-19 14:56:06 +02:00
end
2024-07-24 17:29:40 +02:00
has_air = false
2024-07-19 14:56:06 +02:00
end
end
end
2024-07-23 01:09:17 +02:00
function mcl_villages.find_surface_up(lvm, pos, surface_node)
2024-07-19 14:56:06 +02:00
local p6 = vector.new(pos)
2024-07-23 01:09:17 +02:00
surface_node = surface_node or lvm:get_node_at(p6) --, true, 1000000)
2024-07-19 14:56:06 +02:00
if not surface_node then return end
2024-07-24 17:29:40 +02:00
for y = p6.y + 1, p6.y + 80 do
2024-07-19 14:56:06 +02:00
p6.y = y
2024-07-23 01:09:17 +02:00
local top_node = lvm:get_node_at(p6)
2024-07-24 17:29:40 +02:00
if not top_node or top_node.name == "ignore" then return nil end
2024-07-19 14:56:06 +02:00
if is_above_surface(top_node.name) then
if mcl_villages.surface_mat[surface_node.name] then
2024-07-24 17:29:40 +02:00
-- minetest.log("Found "..surface_node.name.." below "..top_node.name)
2024-07-19 14:56:06 +02:00
p6.y = p6.y - 1
2024-07-23 01:09:17 +02:00
return p6, surface_node
2024-07-24 17:29:40 +02:00
else
local ndef = minetest.registered_nodes[surface_node.name]
if ndef and ndef.walkable then
-- minetest.log("Found non-suitable "..surface_node.name.." below "..top_node.name)
return nil
end
2024-07-19 14:56:06 +02:00
end
end
surface_node = top_node
end
end
-------------------------------------------------------------------------------
-- function to find surface block y coordinate
-- returns surface postion
-------------------------------------------------------------------------------
2024-07-23 01:09:17 +02:00
function mcl_villages.find_surface(lvm, pos)
local p6 = vector.new(pos)
2024-07-19 14:56:06 +02:00
if p6.y < 0 then p6.y = 0 end -- start at water level
2024-07-23 01:09:17 +02:00
local surface_node = lvm:get_node_at(p6)
2024-07-19 14:56:06 +02:00
-- downward, if starting position is empty
if is_above_surface(surface_node.name) then
2024-07-23 01:09:17 +02:00
return mcl_villages.find_surface_down(lvm, p6, surface_node)
2024-07-19 14:56:06 +02:00
else
2024-07-23 01:09:17 +02:00
return mcl_villages.find_surface_up(lvm, p6, surface_node)
end
end
2024-07-23 01:09:17 +02:00
-- check the minimum distance of two squares, on axes
function mcl_villages.check_distance(settlement, cpos, sizex, sizez, limit)
for i, building in ipairs(settlement) do
local opos, osizex, osizez = building.pos, building.size.x, building.size.z
local dx = math.abs(cpos.x - opos.x) - (sizex + osizex) * 0.5
local dz = math.abs(cpos.z - opos.z) - (sizez + osizez) * 0.5
if math.max(dx, dz) < limit then return false end
2021-01-29 19:49:33 +01:00
end
return true
end
-------------------------------------------------------------------------------
-- fill chests
-------------------------------------------------------------------------------
2024-07-19 14:56:06 +02:00
function mcl_villages.fill_chest(pos, pr)
2021-01-29 19:49:33 +01:00
-- initialize chest (mts chests don't have meta)
local meta = minetest.get_meta(pos)
if meta:get_string("infotext") ~= "Chest" then
-- For MineClone2 0.70 or before
2024-07-20 13:57:01 +02:00
minetest.registered_nodes["mcl_chests:chest"].on_construct(pos)
2021-01-29 19:49:33 +01:00
--
-- For MineClone2 after commit 09ab1482b5 (the new entity chests)
minetest.registered_nodes["mcl_chests:chest_small"].on_construct(pos)
end
-- fill chest
local inv = minetest.get_inventory( {type="node", pos=pos} )
2021-04-16 13:35:03 +02:00
local function get_treasures(prand)
2021-01-29 19:49:33 +01:00
local loottable = {{
stacks_min = 3,
stacks_max = 8,
items = {
{ itemstring = "mcl_core:diamond", weight = 3, amount_min = 1, amount_max = 3 },
{ itemstring = "mcl_core:iron_ingot", weight = 10, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:gold_ingot", weight = 5, amount_min = 1, amount_max = 3 },
{ itemstring = "mcl_farming:bread", weight = 15, amount_min = 1, amount_max = 3 },
{ itemstring = "mcl_core:apple", weight = 15, amount_min = 1, amount_max = 3 },
{ itemstring = "mcl_tools:pick_iron", weight = 5 },
{ itemstring = "mcl_tools:sword_iron", weight = 5 },
{ itemstring = "mcl_armor:chestplate_iron", weight = 5 },
{ itemstring = "mcl_armor:helmet_iron", weight = 5 },
{ itemstring = "mcl_armor:leggings_iron", weight = 5 },
{ itemstring = "mcl_armor:boots_iron", weight = 5 },
{ itemstring = "mcl_core:obsidian", weight = 5, amount_min = 3, amount_max = 7 },
{ itemstring = "mcl_core:sapling", weight = 5, amount_min = 3, amount_max = 7 },
{ itemstring = "mcl_mobitems:saddle", weight = 3 },
2022-05-25 23:25:15 +02:00
{ itemstring = "mcl_mobitems:iron_horse_armor", weight = 1 },
{ itemstring = "mcl_mobitems:gold_horse_armor", weight = 1 },
{ itemstring = "mcl_mobitems:diamond_horse_armor", weight = 1 },
}
2021-01-29 19:49:33 +01:00
}}
2021-04-16 13:35:03 +02:00
local items = mcl_loot.get_multi_loot(loottable, prand)
return items
end
2021-01-29 19:49:33 +01:00
local items = get_treasures(pr)
mcl_loot.fill_inventory(inv, "main", items, pr)
end
-------------------------------------------------------------------------------
-- initialize furnace
-------------------------------------------------------------------------------
2024-07-19 14:56:06 +02:00
function mcl_villages.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
-------------------------------------------------------------------------------
2024-07-19 14:56:06 +02:00
function mcl_villages.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
-------------------------------------------------------------------------------
-- randomize table
-------------------------------------------------------------------------------
2024-07-19 14:56:06 +02:00
function mcl_villages.shuffle(tbl, pr)
local copy = {}
for key, value in ipairs(tbl) do
table.insert(copy, pr:next(1, #copy + 1), value)
end
2024-07-19 14:56:06 +02:00
return copy
end
2024-07-19 14:56:06 +02:00
-- Load a schema and replace nodes in it based on biome
function mcl_villages.substitute_materials(pos, schem_lua, pr)
local modified_schem_lua = schem_lua
local biome_data = minetest.get_biome_data(pos)
local biome_name = minetest.get_biome_name(biome_data.biome)
2024-07-20 02:10:25 +02:00
-- for now, map to MCLA, later back, so we can keep their rules unchanged
for _, sub in pairs(mcl_villages.vl_to_mcla) do
modified_schem_lua = modified_schem_lua:gsub(sub[1], sub[2])
end
2024-07-19 14:56:06 +02:00
if mcl_villages.biome_map[biome_name] and mcl_villages.material_substitions[mcl_villages.biome_map[biome_name]] then
for _, sub in pairs(mcl_villages.material_substitions[mcl_villages.biome_map[biome_name]]) do
modified_schem_lua = modified_schem_lua:gsub(sub[1], sub[2])
end
end
2024-07-20 02:10:25 +02:00
-- MCLA node names back to VL
for _, sub in pairs(mcl_villages.mcla_to_vl) do
modified_schem_lua = modified_schem_lua:gsub(sub[1], sub[2])
end
2024-07-19 14:56:06 +02:00
return modified_schem_lua
end
2024-07-19 14:56:06 +02:00
local villages = {}
local mod_storage = minetest.get_mod_storage()
2024-07-19 14:56:06 +02:00
local function lazy_load_village(name)
if not villages[name] then
local data = mod_storage:get("mcl_villages." .. name)
if data then
villages[name] = minetest.deserialize(data)
end
end
2024-07-19 14:56:06 +02:00
end
2024-07-19 14:56:06 +02:00
function mcl_villages.get_village(name)
lazy_load_village(name)
if villages[name] then
return table.copy(villages[name])
end
end
2024-07-19 14:56:06 +02:00
function mcl_villages.village_exists(name)
lazy_load_village(name)
return villages[name] ~= nil
end
function mcl_villages.add_village(name, data)
lazy_load_village(name)
if villages[name] then
minetest.log("info","Village already exists: " .. name )
return false
end
local new_village = {name = name, data = data}
mod_storage:set_string("mcl_villages." .. name, minetest.serialize(new_village))
return true
end