mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-17 08:31:08 +01:00
497 lines
14 KiB
Lua
497 lines
14 KiB
Lua
mcl_villages = {}
|
|
mcl_villages.modpath = minetest.get_modpath(minetest.get_current_modname())
|
|
|
|
local village_chance = tonumber(minetest.settings:get("mcl_villages_village_probability")) or 1
|
|
|
|
dofile(mcl_villages.modpath.."/const.lua")
|
|
dofile(mcl_villages.modpath.."/utils.lua")
|
|
dofile(mcl_villages.modpath.."/foundation.lua")
|
|
dofile(mcl_villages.modpath.."/buildings.lua")
|
|
dofile(mcl_villages.modpath.."/paths.lua")
|
|
dofile(mcl_villages.modpath.."/api.lua")
|
|
|
|
local S = minetest.get_translator(minetest.get_current_modname())
|
|
|
|
minetest.register_alias("mcl_villages:stonebrickcarved", "mcl_core:stonebrickcarved")
|
|
-- In 2025, remove structblock: minetest.register_alias("mcl_villages:structblock", "air")
|
|
minetest.register_node("mcl_villages:structblock", {drawtype="airlike",groups = {not_in_creative_inventory=1},})
|
|
-- we currently do not support/use these from MCLA:
|
|
--minetest.register_alias("mcl_villages:village_block", "air")
|
|
--minetest.register_alias("mcl_villages:no_paths", "air")
|
|
--minetest.register_alias("mcl_villages:path_endpoint", "air")
|
|
--minetest.register_alias("mcl_villages:building_block", "air")
|
|
--
|
|
-- on map generation, try to build a settlement
|
|
--
|
|
local function build_a_settlement(minp, maxp, blockseed)
|
|
if mcl_villages.village_exists(blockseed) then return end
|
|
local pr = PcgRandom(blockseed)
|
|
local lvm = VoxelManip()
|
|
lvm:read_from_map(minp, maxp)
|
|
local settlement = mcl_villages.create_site_plan(lvm, minp, maxp, pr)
|
|
if not settlement then return false, false end
|
|
-- all foundations first, then all buildings, to avoid damaging very close buildings
|
|
mcl_villages.terraform(lvm, settlement, pr)
|
|
mcl_villages.place_schematics(lvm, settlement, blockseed, pr)
|
|
mcl_villages.add_village(blockseed, settlement)
|
|
--lvm:write_to_map(false)
|
|
for _, on_village_placed_callback in pairs(mcl_villages.on_village_placed) do
|
|
on_village_placed_callback(settlement, blockseed)
|
|
end
|
|
end
|
|
|
|
local function ecb_village(blockpos, action, calls_remaining, param)
|
|
if calls_remaining >= 1 then return end
|
|
local minp, maxp, blockseed = param.minp, param.maxp, param.blockseed
|
|
build_a_settlement(minp, maxp, blockseed)
|
|
end
|
|
|
|
-- Disable natural generation in singlenode.
|
|
local mg_name = minetest.get_mapgen_setting("mg_name")
|
|
if mg_name ~= "singlenode" then
|
|
--[[ did not work, because later structure generation would make holes in our schematics
|
|
mcl_mapgen_core.register_generator("villages", function(lvm, data, data2, e1, e2, area, minp, maxp, blockseed)
|
|
if mcl_villages.village_exists(blockseed) then return false, false end
|
|
|
|
lvm:set_data(data) -- FIXME: ugly hack, better directly manipulate the data array
|
|
lvm:set_param2_data(data2)
|
|
local pr = PcgRandom(blockseed)
|
|
if pr:next(0, 100) > village_chance then return end
|
|
local settlement = mcl_villages.create_site_plan(lvm, minp, maxp, pr)
|
|
if not settlement then return false, false end
|
|
|
|
-- all foundations first, then all buildings, to avoid damaging very close buildings
|
|
mcl_villages.terraform(lvm, settlement, pr)
|
|
mcl_villages.place_schematics(lvm, settlement, pr)
|
|
-- TODO: replace with MCLA code: mcl_villages.paths(settlement)
|
|
mcl_villages.add_village(blockseed, settlement)
|
|
lvm:get_data(data) -- FIXME: ugly hack, better directly manipulate the data array
|
|
lvm:get_param2_data(data2)
|
|
return true, true
|
|
end, function(minp, maxp, blockseed)
|
|
for _, on_village_placed_callback in pairs(mcl_villages.on_village_placed) do
|
|
on_village_placed_callback(settlement, blockseed)
|
|
end
|
|
end, 15000)
|
|
]]--
|
|
mcl_mapgen_core.register_generator("villages", nil, function(minp, maxp, blockseed)
|
|
if maxp.y < 0 or mcl_villages.village_exists(blockseed) then return end
|
|
local pr = PcgRandom(blockseed)
|
|
if pr:next(0, 100) > village_chance then return end
|
|
--local lvm, emin, emax = minetest.get_mapgen_object("voxelmanip") -- did not get the lighting fixed?
|
|
local lvm = VoxelManip()
|
|
lvm:read_from_map(minp, maxp)
|
|
local settlement = mcl_villages.create_site_plan(lvm, minp, maxp, pr)
|
|
if not settlement then return false, false end
|
|
-- all foundations first, then all buildings, to avoid damaging very close buildings
|
|
mcl_villages.terraform(lvm, settlement, pr)
|
|
mcl_villages.place_schematics(lvm, settlement, blockseed, pr)
|
|
mcl_villages.add_village(blockseed, settlement)
|
|
--lvm:write_to_map(true)
|
|
--mcl_villages.paths(blockseed) -- TODO: biome
|
|
end, 15000)
|
|
end
|
|
|
|
-- This is a light source so that lamps don't get placed near it
|
|
minetest.register_node("mcl_villages:village_block", {
|
|
drawtype = "airlike",
|
|
groups = { not_in_creative_inventory = 1 },
|
|
light_source = 14,
|
|
|
|
-- Somethings don't work reliably when done in the map building
|
|
-- so we use a timer to run them later when they work more reliably
|
|
-- e.g. spawning mobs, running minetest.find_path
|
|
on_timer = function(pos, elapsed)
|
|
local meta = minetest.get_meta(pos)
|
|
local blockseed = meta:get_string("blockseed")
|
|
local node_type = meta:get_string("node_type")
|
|
minetest.set_node(pos, { name = node_type })
|
|
mcl_villages.post_process_village(blockseed)
|
|
return false
|
|
end,
|
|
})
|
|
|
|
-- LEGACY, for spawning "planned" cities in old maps. Remove in 2025?
|
|
minetest.register_lbm({
|
|
name = "mcl_villages:structblock",
|
|
run_at_every_load = true,
|
|
nodenames = {"mcl_villages:structblock"},
|
|
action = function(pos, node)
|
|
minetest.set_node(pos, {name = "air"})
|
|
local px, py, pz = math.floor(pos.x / 16) * 16, math.floor(pos.y / 16) * 16, math.floor(pos.z / 16) * 16
|
|
local minp=vector.new(px, py, pz)
|
|
local maxp=vector.new(px + 80, py + 80, pz + 80)
|
|
local blockseed = PcgRandom(px * 223 + py * 17 + pz):next()
|
|
minetest.emerge_area(minp, maxp, ecb_village, {minp=minp, maxp=maxp, blockseed=blockseed})
|
|
end
|
|
})
|
|
|
|
-- manually place villages
|
|
if minetest.is_creative_enabled("") then
|
|
minetest.register_craftitem("mcl_villages:tool", {
|
|
description = S("mcl_villages build tool"),
|
|
inventory_image = "default_tool_woodshovel.png",
|
|
-- build settlement
|
|
on_place = function(itemstack, placer, pointed_thing)
|
|
if not pointed_thing.under then return end
|
|
if not minetest.check_player_privs(placer, "server") then
|
|
minetest.chat_send_player(placer:get_player_name(), S("Placement denied. You need the “server” privilege to place villages."))
|
|
return
|
|
end
|
|
local minp = vector.subtract(pointed_thing.under, mcl_villages.half_map_chunk_size)
|
|
local maxp = vector.add(pointed_thing.under, mcl_villages.half_map_chunk_size)
|
|
build_a_settlement(minp, maxp, math.random(0,32767))
|
|
end
|
|
})
|
|
mcl_wip.register_experimental_item("mcl_villages:tool")
|
|
end
|
|
|
|
-- This makes the temporary node invisble unless in creative mode
|
|
local drawtype = "airlike"
|
|
if minetest.is_creative_enabled("") then
|
|
drawtype = "glasslike"
|
|
end
|
|
|
|
minetest.register_node("mcl_villages:no_paths", {
|
|
description = S(
|
|
"Prevent paths from being placed during villager generation. Replaced by air after village path generation"
|
|
),
|
|
paramtype = "light",
|
|
drawtype = drawtype,
|
|
inventory_image = "mcl_core_barrier.png",
|
|
wield_image = "mcl_core_barrier.png",
|
|
tiles = { "mcl_core_barrier.png" },
|
|
is_ground_content = false,
|
|
groups = { creative_breakable = 1, not_solid = 1, not_in_creative_inventory = 1 },
|
|
})
|
|
|
|
minetest.register_node("mcl_villages:path_endpoint", {
|
|
description = S("Mark the node as a good place for paths to connect to"),
|
|
is_ground_content = false,
|
|
tiles = { "wool_white.png" },
|
|
wield_image = "wool_white.png",
|
|
wield_scale = { x = 1, y = 1, z = 0.5 },
|
|
groups = { handy = 1, supported_node = 1, not_in_creative_inventory = 1 },
|
|
sounds = mcl_sounds.node_sound_wool_defaults(),
|
|
paramtype = "light",
|
|
sunlight_propagates = true,
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{ -8 / 16, -8 / 16, -8 / 16, 8 / 16, -7 / 16, 8 / 16 },
|
|
},
|
|
},
|
|
_mcl_hardness = 0.1,
|
|
_mcl_blast_resistance = 0.1,
|
|
})
|
|
|
|
local schem_path = mcl_villages.modpath .. "/schematics/"
|
|
|
|
mcl_villages.register_bell({ name = "belltower", mts = schem_path .. "new_villages/belltower.mts", yadjust = 1 })
|
|
|
|
mcl_villages.register_well({
|
|
name = "well",
|
|
mts = schem_path .. "new_villages/well.mts",
|
|
yadjust = -1,
|
|
})
|
|
|
|
for i = 1, 6 do
|
|
mcl_villages.register_lamp({
|
|
name = "lamp",
|
|
mts = schem_path .. "new_villages/lamp_" .. i .. ".mts",
|
|
yadjust = 1,
|
|
no_ground_turnip = true,
|
|
no_clearance = true,
|
|
})
|
|
end
|
|
|
|
mcl_villages.register_building({
|
|
name = "house_big",
|
|
mts = schem_path .. "new_villages/house_4_bed.mts",
|
|
min_jobs = 6,
|
|
max_jobs = 99,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "house_large",
|
|
mts = schem_path .. "new_villages/house_3_bed.mts",
|
|
min_jobs = 4,
|
|
max_jobs = 99,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "house_medium",
|
|
mts = schem_path .. "new_villages/house_2_bed.mts",
|
|
min_jobs = 2,
|
|
max_jobs = 99,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "house_chimney",
|
|
mts = schem_path .. "haeuschen2.mts",
|
|
min_jobs = 2,
|
|
max_jobs = 99,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "house_small",
|
|
mts = schem_path .. "new_villages/house_1_bed.mts",
|
|
min_jobs = 1,
|
|
max_jobs = 99,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "blacksmith",
|
|
mts = schem_path .. "new_villages/blacksmith.mts",
|
|
num_others = 8,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "butcher",
|
|
mts = schem_path .. "new_villages/butcher.mts",
|
|
num_others = 8,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "farm",
|
|
mts = schem_path .. "new_villages/farm.mts",
|
|
num_others = 3,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "fish_farm",
|
|
mts = schem_path .. "new_villages/fishery.mts",
|
|
num_others = 8,
|
|
yadjust = -2,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "fletcher",
|
|
mts = schem_path .. "bogner.mts",
|
|
num_others = 8,
|
|
yadjust = 0,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "library",
|
|
mts = schem_path .. "new_villages/library.mts",
|
|
min_jobs = 12,
|
|
max_jobs = 99,
|
|
num_others = 15,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "librarian",
|
|
mts = schem_path .. "schreiber.mts",
|
|
min_jobs = 1,
|
|
max_jobs = 11,
|
|
yadjust = 0,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "map_shop",
|
|
mts = schem_path .. "new_villages/cartographer.mts",
|
|
num_others = 15,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "mason",
|
|
mts = schem_path .. "new_villages/mason.mts",
|
|
num_others = 8,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "mill",
|
|
mts = schem_path .. "new_villages/mill.mts",
|
|
num_others = 8,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "tannery",
|
|
mts = schem_path .. "new_villages/leather_worker.mts",
|
|
num_others = 8,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "tool_smith",
|
|
mts = schem_path .. "new_villages/toolsmith.mts",
|
|
num_others = 8,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "weapon_smith",
|
|
mts = schem_path .. "new_villages/weaponsmith.mts",
|
|
num_others = 8,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "chapel",
|
|
mts = schem_path .. "new_villages/chapel.mts",
|
|
num_others = 8,
|
|
min_jobs = 1,
|
|
max_jobs = 9,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "church",
|
|
mts = schem_path .. "kirche.mts",
|
|
num_others = 20,
|
|
min_jobs = 10,
|
|
max_jobs = 99,
|
|
yadjust = 0,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "farm_small",
|
|
mts = schem_path .. "new_villages/farm_small_1.mts",
|
|
num_others = 3,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "farm_small2",
|
|
mts = schem_path .. "new_villages/farm_small_2.mts",
|
|
num_others = 3,
|
|
yadjust = 1,
|
|
})
|
|
|
|
mcl_villages.register_building({
|
|
name = "farm_large",
|
|
mts = schem_path .. "new_villages/farm_large_1.mts",
|
|
num_others = 6,
|
|
yadjust = 1,
|
|
})
|
|
|
|
for _, crop_type in pairs(mcl_villages.get_crop_types()) do
|
|
for count = 1, 8 do
|
|
local tile = crop_type .. "_" .. count .. ".png"
|
|
minetest.register_node("mcl_villages:crop_" .. crop_type .. "_" .. count, {
|
|
description = S("A place to plant @1 crops", crop_type),
|
|
is_ground_content = false,
|
|
tiles = { tile },
|
|
wield_image = tile,
|
|
wield_scale = { x = 1, y = 1, z = 0.5 },
|
|
groups = { handy = 1, supported_node = 1, not_in_creative_inventory = 1 },
|
|
paramtype = "light",
|
|
sunlight_propagates = true,
|
|
drawtype = "nodebox",
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{ -8 / 16, -8 / 16, -8 / 16, 8 / 16, -7 / 16, 8 / 16 },
|
|
},
|
|
},
|
|
_mcl_hardness = 0.1,
|
|
_mcl_blast_resistance = 0.1,
|
|
})
|
|
end
|
|
end
|
|
|
|
mcl_villages.register_crop({
|
|
type = "grain",
|
|
node = "mcl_farming:wheat_1",
|
|
biomes = {
|
|
acacia = 10,
|
|
bamboo = 10,
|
|
desert = 10,
|
|
jungle = 10,
|
|
plains = 10,
|
|
savanna = 10,
|
|
spruce = 10,
|
|
},
|
|
})
|
|
|
|
mcl_villages.register_crop({
|
|
type = "root",
|
|
node = "mcl_farming:carrot_1",
|
|
biomes = {
|
|
acacia = 10,
|
|
bamboo = 6,
|
|
desert = 10,
|
|
jungle = 6,
|
|
plains = 6,
|
|
spruce = 10,
|
|
},
|
|
})
|
|
|
|
mcl_villages.register_crop({
|
|
type = "root",
|
|
node = "mcl_farming:potato_1",
|
|
biomes = {
|
|
acacia = 6,
|
|
bamboo = 10,
|
|
desert = 6,
|
|
jungle = 10,
|
|
plains = 10,
|
|
spruce = 6,
|
|
},
|
|
})
|
|
|
|
mcl_villages.register_crop({
|
|
type = "root",
|
|
node = "mcl_farming:beetroot_0",
|
|
biomes = {
|
|
acacia = 3,
|
|
bamboo = 3,
|
|
desert = 3,
|
|
jungle = 3,
|
|
plains = 3,
|
|
spruce = 3,
|
|
},
|
|
})
|
|
|
|
mcl_villages.register_crop({
|
|
type = "gourd",
|
|
node = "mcl_farming:melontige_1",
|
|
biomes = {
|
|
bamboo = 10,
|
|
jungle = 10,
|
|
},
|
|
})
|
|
|
|
mcl_villages.register_crop({
|
|
type = "gourd",
|
|
node = "mcl_farming:pumpkin_1",
|
|
biomes = {
|
|
acacia = 10,
|
|
bamboo = 5,
|
|
desert = 10,
|
|
jungle = 5,
|
|
plains = 10,
|
|
spruce = 10,
|
|
},
|
|
})
|
|
|
|
for name, def in pairs(minetest.registered_nodes) do
|
|
if def.groups["flower"] and not def.groups["double_plant"] and name ~= "mcl_flowers:wither_rose" then
|
|
mcl_villages.register_crop({
|
|
type = "flower",
|
|
node = name,
|
|
biomes = {
|
|
acacia = 10,
|
|
bamboo = 6,
|
|
desert = 10,
|
|
jungle = 6,
|
|
plains = 6,
|
|
spruce = 10,
|
|
},
|
|
})
|
|
end
|
|
end
|