Skip to content

Commit

Permalink
Decorations: Generalise 'spawn by' to be used by all decoration types
Browse files Browse the repository at this point in the history
In lua_api.txt, make clear that 'place on' and 'spawn by' can be lists.
  • Loading branch information
paramat committed Sep 14, 2016
1 parent b77cee1 commit b885950
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 85 deletions.
16 changes: 8 additions & 8 deletions doc/lua_api.txt
Expand Up @@ -3909,7 +3909,7 @@ The Biome API is still in an experimental phase and subject to change.
{
deco_type = "simple", -- See "Decoration types"
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,
-- ^ 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.
Expand All @@ -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.
-- ^ This parameter refers to the `y` position of the decoration base, so
-- 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 for all decoration types.
-- ^ "liquid_surface": Instead of placement on the highest solid surface
Expand All @@ -3945,13 +3952,6 @@ The Biome API is still in an experimental phase and subject to change.
height_max = 0,
-- ^ Number of nodes the decoration can be at maximum.
-- ^ 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 = "foobar.mts",
Expand Down
119 changes: 58 additions & 61 deletions src/mg_decoration.cpp
Expand Up @@ -26,12 +26,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"

FlagDesc flagdesc_deco[] = {
{"place_center_x", DECO_PLACE_CENTER_X},
{"place_center_y", DECO_PLACE_CENTER_Y},
{"place_center_z", DECO_PLACE_CENTER_Z},
{"place_center_x", DECO_PLACE_CENTER_X},
{"place_center_y", DECO_PLACE_CENTER_Y},
{"place_center_z", DECO_PLACE_CENTER_Z},
{"force_placement", DECO_FORCE_PLACEMENT},
{"liquid_surface", DECO_LIQUID_SURFACE},
{NULL, 0}
{"liquid_surface", DECO_LIQUID_SURFACE},
{NULL, 0}
};


Expand Down Expand Up @@ -82,6 +82,56 @@ Decoration::~Decoration()
void Decoration::resolveNodeNames()
{
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;
}


Expand Down Expand Up @@ -236,66 +286,15 @@ void DecoSimple::resolveNodeNames()
{
Decoration::resolveNodeNames();
getIdsFromNrBacklog(&c_decos);
getIdsFromNrBacklog(&c_spawnby);
}


bool DecoSimple::canPlaceDecoration(MMVManip *vm, 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 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;
}

return 0;

size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p)
{
if (!canPlaceDecoration(vm, p))
return 0;

Expand Down Expand Up @@ -345,9 +344,7 @@ size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p)
if (schematic == NULL)
return 0;

u32 vi = vm->m_area.index(p);
content_t c = vm->m_data[vi].getContent();
if (!CONTAINS(c_place_on, c))
if (!canPlaceDecoration(vm, p))
return 0;

if (flags & DECO_PLACE_CENTER_X)
Expand Down
9 changes: 4 additions & 5 deletions src/mg_decoration.h
Expand Up @@ -68,6 +68,7 @@ class Decoration : public ObjDef, public NodeResolver {

virtual void resolveNodeNames();

bool canPlaceDecoration(MMVManip *vm, v3s16 p);
size_t placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
//size_t placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);

Expand All @@ -82,6 +83,8 @@ class Decoration : public ObjDef, public NodeResolver {
s16 y_max;
float fill_ratio;
NoiseParams np;
std::vector<content_t> c_spawnby;
s16 nspawnby;

UNORDERED_SET<u8> biomes;
//std::list<CutoffData> cutoffs;
Expand All @@ -90,17 +93,13 @@ class Decoration : public ObjDef, public NodeResolver {

class DecoSimple : public Decoration {
public:
virtual void resolveNodeNames();
virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p);
bool canPlaceDecoration(MMVManip *vm, v3s16 p);
virtual int getHeight();

virtual void resolveNodeNames();

std::vector<content_t> c_decos;
std::vector<content_t> c_spawnby;
s16 deco_height;
s16 deco_height_max;
s16 nspawnby;
};

class DecoSchematic : public Decoration {
Expand Down
21 changes: 10 additions & 11 deletions src/script/lua_api/l_mapgen.cpp
Expand Up @@ -902,6 +902,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02);
deco->y_min = getintfield_default(L, index, "y_min", -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);
if (deco->sidelen <= 0) {
errorstream << "register_decoration: sidelen must be "
Expand Down Expand Up @@ -929,6 +930,14 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
errorstream << "register_decoration: couldn't get all biomes " << std::endl;
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
bool success = false;
switch (decotype) {
Expand Down Expand Up @@ -962,35 +971,25 @@ int ModApiMapgen::l_register_decoration(lua_State *L)

bool read_deco_simple(lua_State *L, DecoSimple *deco)
{
size_t nnames;
int index = 1;

deco->deco_height = getintfield_default(L, index, "height", 1);
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) {
errorstream << "register_decoration: simple decoration height"
" must be greater than 0" << std::endl;
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);
if (nnames == 0) {
errorstream << "register_decoration: no decoration nodes "
"defined" << std::endl;
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;
}

Expand Down

0 comments on commit b885950

Please sign in to comment.