Decorations: Generalise 'spawn by' to be used by all decoration types

In lua_api.txt, make clear that 'place on' and 'spawn by' can be lists.
This commit is contained in:
paramat 2016-09-11 23:34:43 +01:00
parent b77cee146b
commit b88595050f
4 changed files with 82 additions and 87 deletions

@ -3909,7 +3909,7 @@ The Biome API is still in an experimental phase and subject to change.
{ {
deco_type = "simple", -- See "Decoration types" deco_type = "simple", -- See "Decoration types"
place_on = "default:dirt_with_grass", place_on = "default:dirt_with_grass",
-- ^ Node that decoration can be placed on -- ^ Node (or list of nodes) that the decoration can be placed on
sidelen = 8, sidelen = 8,
-- ^ Size of divisions made in the chunk being generated. -- ^ Size of divisions made in the chunk being generated.
-- ^ If the chunk size is not evenly divisible by sidelen, sidelen is made equal to the chunk size. -- ^ If the chunk size is not evenly divisible by sidelen, sidelen is made equal to the chunk size.
@ -3928,6 +3928,13 @@ The Biome API is still in an experimental phase and subject to change.
-- ^ Minimum and maximum `y` positions these decorations can be generated at. -- ^ Minimum and maximum `y` positions these decorations can be generated at.
-- ^ This parameter refers to the `y` position of the decoration base, so -- ^ This parameter refers to the `y` position of the decoration base, so
-- the actual maximum height would be `height_max + size.Y`. -- the actual maximum height would be `height_max + size.Y`.
spawn_by = "default:water",
-- ^ Node (or list of nodes) that the decoration only spawns next to.
-- ^ Checks two horizontal planes of neighbouring nodes (including diagonal neighbours),
-- ^ one plane at Y = surface and one plane at Y = surface = + 1.
num_spawn_by = 1,
-- ^ Number of spawn_by nodes that must be surrounding the decoration position to occur.
-- ^ If absent or -1, decorations occur next to any nodes.
flags = "liquid_surface, force_placement", flags = "liquid_surface, force_placement",
-- ^ Flags for all decoration types. -- ^ Flags for all decoration types.
-- ^ "liquid_surface": Instead of placement on the highest solid surface -- ^ "liquid_surface": Instead of placement on the highest solid surface
@ -3945,13 +3952,6 @@ The Biome API is still in an experimental phase and subject to change.
height_max = 0, height_max = 0,
-- ^ Number of nodes the decoration can be at maximum. -- ^ Number of nodes the decoration can be at maximum.
-- ^ If absent, the parameter 'height' is used as a constant. -- ^ If absent, the parameter 'height' is used as a constant.
spawn_by = "default:water",
-- ^ Node that the decoration only spawns next to.
-- ^ The neighbours checked are the 8 nodes horizontally surrounding the lowest node of the
-- ^ decoration, and the 8 nodes horizontally surrounding the ground node below the decoration.
num_spawn_by = 1,
-- ^ Number of spawn_by nodes that must be surrounding the decoration position to occur.
-- ^ If absent or -1, decorations occur next to any nodes.
----- Schematic-type parameters ----- Schematic-type parameters
schematic = "foobar.mts", schematic = "foobar.mts",

@ -82,6 +82,56 @@ Decoration::~Decoration()
void Decoration::resolveNodeNames() void Decoration::resolveNodeNames()
{ {
getIdsFromNrBacklog(&c_place_on); getIdsFromNrBacklog(&c_place_on);
getIdsFromNrBacklog(&c_spawnby);
}
bool Decoration::canPlaceDecoration(MMVManip *vm, v3s16 p)
{
// Check if the decoration can be placed on this node
u32 vi = vm->m_area.index(p);
if (!CONTAINS(c_place_on, vm->m_data[vi].getContent()))
return false;
// Don't continue if there are no spawnby constraints
if (nspawnby == -1)
return true;
int nneighs = 0;
static const v3s16 dirs[16] = {
v3s16( 0, 0, 1),
v3s16( 0, 0, -1),
v3s16( 1, 0, 0),
v3s16(-1, 0, 0),
v3s16( 1, 0, 1),
v3s16(-1, 0, 1),
v3s16(-1, 0, -1),
v3s16( 1, 0, -1),
v3s16( 0, 1, 1),
v3s16( 0, 1, -1),
v3s16( 1, 1, 0),
v3s16(-1, 1, 0),
v3s16( 1, 1, 1),
v3s16(-1, 1, 1),
v3s16(-1, 1, -1),
v3s16( 1, 1, -1)
};
// Check these 16 neighbouring nodes for enough spawnby nodes
for (size_t i = 0; i != ARRLEN(dirs); i++) {
u32 index = vm->m_area.index(p + dirs[i]);
if (!vm->m_area.contains(index))
continue;
if (CONTAINS(c_spawnby, vm->m_data[index].getContent()))
nneighs++;
}
if (nneighs < nspawnby)
return false;
return true;
} }
@ -236,66 +286,15 @@ void DecoSimple::resolveNodeNames()
{ {
Decoration::resolveNodeNames(); Decoration::resolveNodeNames();
getIdsFromNrBacklog(&c_decos); getIdsFromNrBacklog(&c_decos);
getIdsFromNrBacklog(&c_spawnby);
}
bool DecoSimple::canPlaceDecoration(MMVManip *vm, v3s16 p)
{
// Don't bother if there aren't any decorations to place
if (c_decos.size() == 0)
return false;
u32 vi = vm->m_area.index(p);
// Check if the decoration can be placed on this node
if (!CONTAINS(c_place_on, vm->m_data[vi].getContent()))
return false;
// Don't continue if there are no spawnby constraints
if (nspawnby == -1)
return true;
int nneighs = 0;
v3s16 dirs[16] = {
v3s16( 0, 0, 1),
v3s16( 0, 0, -1),
v3s16( 1, 0, 0),
v3s16(-1, 0, 0),
v3s16( 1, 0, 1),
v3s16(-1, 0, 1),
v3s16(-1, 0, -1),
v3s16( 1, 0, -1),
v3s16( 0, 1, 1),
v3s16( 0, 1, -1),
v3s16( 1, 1, 0),
v3s16(-1, 1, 0),
v3s16( 1, 1, 1),
v3s16(-1, 1, 1),
v3s16(-1, 1, -1),
v3s16( 1, 1, -1)
};
// Check a Moore neighborhood if there are enough spawnby nodes
for (size_t i = 0; i != ARRLEN(dirs); i++) {
u32 index = vm->m_area.index(p + dirs[i]);
if (!vm->m_area.contains(index))
continue;
if (CONTAINS(c_spawnby, vm->m_data[index].getContent()))
nneighs++;
}
if (nneighs < nspawnby)
return false;
return true;
} }
size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p) size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p)
{ {
// Don't bother if there aren't any decorations to place
if (c_decos.size() == 0)
return 0;
if (!canPlaceDecoration(vm, p)) if (!canPlaceDecoration(vm, p))
return 0; return 0;
@ -345,9 +344,7 @@ size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p)
if (schematic == NULL) if (schematic == NULL)
return 0; return 0;
u32 vi = vm->m_area.index(p); if (!canPlaceDecoration(vm, p))
content_t c = vm->m_data[vi].getContent();
if (!CONTAINS(c_place_on, c))
return 0; return 0;
if (flags & DECO_PLACE_CENTER_X) if (flags & DECO_PLACE_CENTER_X)

@ -68,6 +68,7 @@ public:
virtual void resolveNodeNames(); virtual void resolveNodeNames();
bool canPlaceDecoration(MMVManip *vm, v3s16 p);
size_t placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); size_t placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
//size_t placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); //size_t placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
@ -82,6 +83,8 @@ public:
s16 y_max; s16 y_max;
float fill_ratio; float fill_ratio;
NoiseParams np; NoiseParams np;
std::vector<content_t> c_spawnby;
s16 nspawnby;
UNORDERED_SET<u8> biomes; UNORDERED_SET<u8> biomes;
//std::list<CutoffData> cutoffs; //std::list<CutoffData> cutoffs;
@ -90,17 +93,13 @@ public:
class DecoSimple : public Decoration { class DecoSimple : public Decoration {
public: public:
virtual void resolveNodeNames();
virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p); virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p);
bool canPlaceDecoration(MMVManip *vm, v3s16 p);
virtual int getHeight(); virtual int getHeight();
virtual void resolveNodeNames();
std::vector<content_t> c_decos; std::vector<content_t> c_decos;
std::vector<content_t> c_spawnby;
s16 deco_height; s16 deco_height;
s16 deco_height_max; s16 deco_height_max;
s16 nspawnby;
}; };
class DecoSchematic : public Decoration { class DecoSchematic : public Decoration {

@ -902,6 +902,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
deco->y_min = getintfield_default(L, index, "y_min", -31000); deco->y_min = getintfield_default(L, index, "y_min", -31000);
deco->y_max = getintfield_default(L, index, "y_max", 31000); deco->y_max = getintfield_default(L, index, "y_max", 31000);
deco->nspawnby = getintfield_default(L, index, "num_spawn_by", -1);
deco->sidelen = getintfield_default(L, index, "sidelen", 8); deco->sidelen = getintfield_default(L, index, "sidelen", 8);
if (deco->sidelen <= 0) { if (deco->sidelen <= 0) {
errorstream << "register_decoration: sidelen must be " errorstream << "register_decoration: sidelen must be "
@ -929,6 +930,14 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
errorstream << "register_decoration: couldn't get all biomes " << std::endl; errorstream << "register_decoration: couldn't get all biomes " << std::endl;
lua_pop(L, 1); lua_pop(L, 1);
//// Get node name(s) to 'spawn by'
size_t nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames);
deco->m_nnlistsizes.push_back(nnames);
if (nnames == 0 && deco->nspawnby != -1) {
errorstream << "register_decoration: no spawn_by nodes defined,"
" but num_spawn_by specified" << std::endl;
}
//// Handle decoration type-specific parameters //// Handle decoration type-specific parameters
bool success = false; bool success = false;
switch (decotype) { switch (decotype) {
@ -962,12 +971,10 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
bool read_deco_simple(lua_State *L, DecoSimple *deco) bool read_deco_simple(lua_State *L, DecoSimple *deco)
{ {
size_t nnames;
int index = 1; int index = 1;
deco->deco_height = getintfield_default(L, index, "height", 1); deco->deco_height = getintfield_default(L, index, "height", 1);
deco->deco_height_max = getintfield_default(L, index, "height_max", 0); deco->deco_height_max = getintfield_default(L, index, "height_max", 0);
deco->nspawnby = getintfield_default(L, index, "num_spawn_by", -1);
if (deco->deco_height <= 0) { if (deco->deco_height <= 0) {
errorstream << "register_decoration: simple decoration height" errorstream << "register_decoration: simple decoration height"
@ -975,7 +982,7 @@ bool read_deco_simple(lua_State *L, DecoSimple *deco)
return false; return false;
} }
nnames = getstringlistfield(L, index, "decoration", &deco->m_nodenames); size_t nnames = getstringlistfield(L, index, "decoration", &deco->m_nodenames);
deco->m_nnlistsizes.push_back(nnames); deco->m_nnlistsizes.push_back(nnames);
if (nnames == 0) { if (nnames == 0) {
errorstream << "register_decoration: no decoration nodes " errorstream << "register_decoration: no decoration nodes "
@ -983,14 +990,6 @@ bool read_deco_simple(lua_State *L, DecoSimple *deco)
return false; return false;
} }
nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames);
deco->m_nnlistsizes.push_back(nnames);
if (nnames == 0 && deco->nspawnby != -1) {
errorstream << "register_decoration: no spawn_by nodes defined,"
" but num_spawn_by specified" << std::endl;
return false;
}
return true; return true;
} }