175 lines
6.1 KiB
Lua
175 lines
6.1 KiB
Lua
|
|
--
|
|
-- Mapgen
|
|
--
|
|
local S = minetest.get_translator("village")
|
|
|
|
local spawn_pos = minetest.setting_get_pos("static_spawnpoint") or {x = 0, y = 0, z = 0}
|
|
local spawn_radius = minetest.settings:get("static_spawn_radius") or 256
|
|
local mapseed = minetest.get_mapgen_setting("seed")
|
|
|
|
local bitwise_and = function(x,y)
|
|
local upper = math.floor(math.log(x, 2))
|
|
local sum = 0
|
|
for n=0, upper do
|
|
sum = sum + math.pow(2, n) * (math.floor(x/math.pow(2, n)) % 2) * ( math.floor(y / math.pow(2, n)) % 2)
|
|
end
|
|
return math.floor(sum)
|
|
end
|
|
|
|
local shortseed = bitwise_and(mapseed, 0xFFFFFF)
|
|
|
|
-- Nodes
|
|
|
|
local place_priv = function(itemstack, placer, pointed_thing)
|
|
if not minetest.get_player_privs(placer:get_player_name()).maphack then
|
|
minetest.chat_send_player(placer:get_player_name(), minetest.colorize("#FF0000", S("You need the “maphack” privilege to use this.")))
|
|
return itemstack
|
|
end
|
|
return minetest.item_place(itemstack, placer, pointed_thing)
|
|
end
|
|
|
|
minetest.register_node(
|
|
"village:entity_spawner",
|
|
{
|
|
description = S("Village Entity Spawner"),
|
|
_tt_help = S("Placeholder that marks a position at which to spawn an entity during village generation"),
|
|
drawtype = "airlike",
|
|
pointable = false,
|
|
inventory_image = "village_entity.png",
|
|
wield_image = "village_entity.png",
|
|
is_ground_content = true,
|
|
sunlight_propagates = true,
|
|
paramtype = "light",
|
|
walkable = false,
|
|
floodable = true,
|
|
buildable_to = true,
|
|
drop = "",
|
|
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
|
|
sounds = default.node_sound_defaults(),
|
|
on_place = place_priv,
|
|
on_timer = function(pos, elapsed)
|
|
-- Wait until some objects are nearby ...
|
|
local objs_around = minetest.get_objects_inside_radius(pos, 12)
|
|
-- ... but not TOO nearby (occupying the pos)
|
|
local objs_near = minetest.get_objects_inside_radius(pos, 1.2)
|
|
if #objs_around > 0 and #objs_near == 0 then
|
|
local ent_name = minetest.get_meta(pos):get_string("entity")
|
|
if ent_name ~= "" then
|
|
local ent = minetest.add_entity({x=pos.x, y=pos.y+0.6, z=pos.z}, ent_name)
|
|
-- All spawned animals are tamed
|
|
if ent ~= nil and ent:get_luaentity() ~= nil then
|
|
if minetest.registered_entities[ent_name].type == "animal" then
|
|
ent:get_luaentity().tamed = true
|
|
end
|
|
end
|
|
else
|
|
minetest.log("error", "[village] Entity spawner without 'entity' in meta set @ "..minetest.pos_to_string(pos))
|
|
end
|
|
minetest.remove_node(pos)
|
|
return
|
|
else
|
|
-- Don't spawn and try again later
|
|
minetest.get_node_timer(pos):start(5)
|
|
end
|
|
end,
|
|
})
|
|
|
|
minetest.register_node(
|
|
"village:grassland_village",
|
|
{
|
|
description = S("Village Spawner"),
|
|
_tt_help = S("Generates a village when placed"),
|
|
tiles = {
|
|
"village_gen.png", "village_gen.png", "village_gen.png",
|
|
"village_gen.png", "village_gen.png^[transformFX", "village_gen.png^[transformFX",
|
|
},
|
|
is_ground_content = false,
|
|
groups = {dig_immediate = 2},
|
|
sounds = default.node_sound_dirt_defaults(),
|
|
drop = "",
|
|
|
|
on_place = place_priv,
|
|
on_construct = function(pos)
|
|
minetest.remove_node(pos)
|
|
|
|
local pr = PseudoRandom(shortseed + pos.x + pos.y + pos.z)
|
|
|
|
-- Spawn village on placement.
|
|
-- Guarantee that at least the well is placed, to avoid confusion.
|
|
village.spawn_village({x=pos.x,y=pos.y-1,z=pos.z}, pr, true)
|
|
end,
|
|
})
|
|
|
|
local function attempt_village_spawn(pos)
|
|
local spos = table.copy(pos)
|
|
spos.y = spos.y + 1
|
|
if minetest.settings:get_bool("mapgen_disable_villages") == true then
|
|
return
|
|
end
|
|
|
|
local pr = PseudoRandom(shortseed + spos.x + spos.y + spos.z)
|
|
|
|
if ((shortseed + spos.x + spos.y + spos.z) % 30) == 1 then
|
|
local nearest = village.get_nearest_village(spos)
|
|
|
|
if nearest.dist > village.min_spawn_dist then
|
|
if vector.distance(spawn_pos, spos) > spawn_radius then
|
|
minetest.log("action", "[village] Spawning a grassland village at " .. "(" .. spos.x
|
|
.. ", " .. spos.y .. ", " .. spos.z .. ")")
|
|
local ok = village.spawn_village({x=spos.x,y=spos.y-1,z=spos.z}, pr)
|
|
if not ok then
|
|
minetest.log("action", "[village] Village spawn failed")
|
|
end
|
|
else
|
|
minetest.log("action", "[village] Cannot spawn village, too near the static spawnpoint")
|
|
end
|
|
else
|
|
minetest.log("action", "[village] Cannot spawn village, too near another village")
|
|
end
|
|
end
|
|
end
|
|
|
|
local village_decoration_id
|
|
if not minetest.settings:get_bool("mapgen_disable_villages") then
|
|
-- Dummy decoration to find possible village spawn points
|
|
-- via gennotify.
|
|
minetest.register_decoration(
|
|
{
|
|
name = "village_grassland",
|
|
deco_type = "schematic",
|
|
place_on = "default:dirt_with_grass",
|
|
sidelen = 16,
|
|
fill_ratio = 0.005,
|
|
biomes = {
|
|
"Grassland",
|
|
},
|
|
-- empty schematic
|
|
schematic = {
|
|
size = { x = 1, y = 1, z = 1 },
|
|
data = {
|
|
{ name = "air", prob = 0 },
|
|
},
|
|
},
|
|
y_min = 1,
|
|
y_max = 1000,
|
|
})
|
|
village_decoration_id = minetest.get_decoration_id("village_grassland")
|
|
|
|
if village_decoration_id then
|
|
minetest.set_gen_notify({decoration=true}, {village_decoration_id})
|
|
minetest.register_on_generated(function(minp, maxp, blockseed)
|
|
local mgobj = minetest.get_mapgen_object("gennotify")
|
|
local deco = mgobj["decoration#"..village_decoration_id]
|
|
if deco then
|
|
for d=1, #deco do
|
|
attempt_village_spawn(deco[d])
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- Legacy alias
|
|
minetest.register_alias("village:grassland_village_mg", "air")
|