1
0

Villages have min and max density setting.

Also made roads use 3+9 scheme, instead of 3+5, for the house connectors.

Fixes #1020.
This commit is contained in:
madmaxoft 2014-05-22 21:47:56 +02:00
parent ebb1ef237a
commit 6aa7df367f
5 changed files with 110 additions and 17 deletions

View File

@ -408,10 +408,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
} }
else if (NoCaseCompare(*itr, "Villages") == 0) else if (NoCaseCompare(*itr, "Villages") == 0)
{ {
int GridSize = a_IniFile.GetValueSetI("Generator", "VillageGridSize", 384); int GridSize = a_IniFile.GetValueSetI("Generator", "VillageGridSize", 384);
int MaxDepth = a_IniFile.GetValueSetI("Generator", "VillageMaxDepth", 3); int MaxDepth = a_IniFile.GetValueSetI("Generator", "VillageMaxDepth", 2);
int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128); int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
m_FinishGens.push_back(new cVillageGen(Seed, GridSize, MaxDepth, MaxSize, *m_BiomeGen, *m_HeightGen)); int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
m_FinishGens.push_back(new cVillageGen(Seed, GridSize, MaxDepth, MaxSize, MinDensity, MaxDensity, *m_BiomeGen, *m_HeightGen));
} }
else if (NoCaseCompare(*itr, "WaterLakes") == 0) else if (NoCaseCompare(*itr, "WaterLakes") == 0)
{ {

View File

@ -308,6 +308,15 @@ cPiece::cConnector cPlacedPiece::GetRotatedConnector(size_t a_Index) const
cPiece::cConnector cPlacedPiece::GetRotatedConnector(const cPiece::cConnector & a_Connector) const
{
return m_Piece->RotateMoveConnector(a_Connector, m_NumCCWRotations, m_Coords.x, m_Coords.y, m_Coords.z);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cPieceGenerator: // cPieceGenerator:

View File

@ -110,6 +110,7 @@ public:
virtual cPieces GetStartingPieces(void) = 0; virtual cPieces GetStartingPieces(void) = 0;
/** Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPiece through a_ExistingConnector. /** Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPiece through a_ExistingConnector.
a_ExistingConnector is the original connector, before any movement or rotation is applied to it.
This allows the pool to tweak the piece's chances, based on the previous pieces in the tree and the connector used. This allows the pool to tweak the piece's chances, based on the previous pieces in the tree and the connector used.
The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will never be chosen. The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will never be chosen.
*/ */
@ -151,6 +152,10 @@ public:
Undefined behavior if a_Index is out of range. */ Undefined behavior if a_Index is out of range. */
cPiece::cConnector GetRotatedConnector(size_t a_Index) const; cPiece::cConnector GetRotatedConnector(size_t a_Index) const;
/** Returns a copy of the specified connector, modified to account for the translation and rotation for
this placement. */
cPiece::cConnector GetRotatedConnector(const cPiece::cConnector & a_Connector) const;
protected: protected:
const cPlacedPiece * m_Parent; const cPlacedPiece * m_Parent;
const cPiece * m_Piece; const cPiece * m_Piece;

View File

@ -27,11 +27,16 @@ though, the roads are generated by code and their content is ignored. A special
class is used, so that the roads connect to each other and to the well only in predefined manners. class is used, so that the roads connect to each other and to the well only in predefined manners.
The well has connectors of type "2". The houses have connectors of type "-1". The roads have connectors of The well has connectors of type "2". The houses have connectors of type "-1". The roads have connectors of
both types' opposites, type "-2" at the far ends and type "1" on the long edges. both types' opposites, type "-2" at the far ends and type "1" on the long edges. Additionally, there are
type "2" connectors along the long edges of the roads as well, so that the roads create T junctions.
When the village is about to be drawn into a chunk, it queries the heights for each piece intersecting the When the village is about to be drawn into a chunk, it queries the heights for each piece intersecting the
chunk. The pieces are shifted so that their pivot points lie on the surface, and the roads are drawn chunk. The pieces are shifted so that their pivot points lie on the surface, and the roads are drawn
directly by turning the surface blocks into gravel / sandstone. directly by turning the surface blocks into gravel / sandstone.
The village prefabs are stored in global piecepools (one pool per village type). In order to support
per-village density setting, the cVillage class itself implements the cPiecePool interface, relaying the
calls to the underlying cVillagePiecePool, after processing the density check.
*/ */
class cVillagePiecePool : class cVillagePiecePool :
@ -46,7 +51,7 @@ public:
super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs) super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs)
{ {
// Add the road pieces: // Add the road pieces:
for (int len = 19; len < 60; len += 8) for (int len = 27; len < 60; len += 12)
{ {
cBlockArea BA; cBlockArea BA;
BA.Create(len, 1, 3, cBlockArea::baTypes | cBlockArea::baMetas); BA.Create(len, 1, 3, cBlockArea::baTypes | cBlockArea::baMetas);
@ -56,14 +61,14 @@ public:
RoadPiece->AddConnector(len - 1, 0, 1, BLOCK_FACE_XP, -2); RoadPiece->AddConnector(len - 1, 0, 1, BLOCK_FACE_XP, -2);
// Add the road connectors: // Add the road connectors:
for (int x = 1; x < len; x += 8) for (int x = 1; x < len; x += 12)
{ {
RoadPiece->AddConnector(x, 0, 0, BLOCK_FACE_ZM, 2); RoadPiece->AddConnector(x, 0, 0, BLOCK_FACE_ZM, 2);
RoadPiece->AddConnector(x, 0, 2, BLOCK_FACE_ZP, 2); RoadPiece->AddConnector(x, 0, 2, BLOCK_FACE_ZP, 2);
} }
// Add the buildings connectors: // Add the buildings connectors:
for (int x = 5; x < len; x += 8) for (int x = 7; x < len; x += 12)
{ {
RoadPiece->AddConnector(x, 0, 0, BLOCK_FACE_ZM, 1); RoadPiece->AddConnector(x, 0, 0, BLOCK_FACE_ZM, 1);
RoadPiece->AddConnector(x, 0, 2, BLOCK_FACE_ZP, 1); RoadPiece->AddConnector(x, 0, 2, BLOCK_FACE_ZP, 1);
@ -94,7 +99,8 @@ public:
class cVillageGen::cVillage : class cVillageGen::cVillage :
public cGridStructGen::cStructure public cGridStructGen::cStructure,
protected cPiecePool
{ {
typedef cGridStructGen::cStructure super; typedef cGridStructGen::cStructure super;
@ -104,7 +110,8 @@ public:
int a_OriginX, int a_OriginZ, int a_OriginX, int a_OriginZ,
int a_MaxRoadDepth, int a_MaxRoadDepth,
int a_MaxSize, int a_MaxSize,
cPrefabPiecePool & a_Prefabs, int a_Density,
cPiecePool & a_Prefabs,
cTerrainHeightGen & a_HeightGen, cTerrainHeightGen & a_HeightGen,
BLOCKTYPE a_RoadBlock BLOCKTYPE a_RoadBlock
) : ) :
@ -112,12 +119,13 @@ public:
m_Seed(a_Seed), m_Seed(a_Seed),
m_Noise(a_Seed), m_Noise(a_Seed),
m_MaxSize(a_MaxSize), m_MaxSize(a_MaxSize),
m_Density(a_Density),
m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, 255, a_OriginZ + a_MaxSize), m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, 255, a_OriginZ + a_MaxSize),
m_Prefabs(a_Prefabs), m_Prefabs(a_Prefabs),
m_HeightGen(a_HeightGen), m_HeightGen(a_HeightGen),
m_RoadBlock(a_RoadBlock) m_RoadBlock(a_RoadBlock)
{ {
cBFSPieceGenerator pg(m_Prefabs, a_Seed); cBFSPieceGenerator pg(*this, a_Seed);
// Generate the pieces at very negative Y coords, so that we can later test // Generate the pieces at very negative Y coords, so that we can later test
// Piece has negative Y coord -> hasn't been height-adjusted yet // Piece has negative Y coord -> hasn't been height-adjusted yet
pg.PlacePieces(a_OriginX, -1000, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces); pg.PlacePieces(a_OriginX, -1000, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces);
@ -133,11 +141,14 @@ protected:
/** Maximum size, in X/Z blocks, of the village (radius from the origin) */ /** Maximum size, in X/Z blocks, of the village (radius from the origin) */
int m_MaxSize; int m_MaxSize;
/** The density for this village. Used to refrain from populating all house connectors. Range [0, 100] */
int m_Density;
/** Borders of the vilalge - no item may reach out of this cuboid. */ /** Borders of the vilalge - no item may reach out of this cuboid. */
cCuboid m_Borders; cCuboid m_Borders;
/** Prefabs to use for buildings */ /** Prefabs to use for buildings */
cPrefabPiecePool & m_Prefabs; cPiecePool & m_Prefabs;
/** The underlying height generator, used for placing the structures on top of the terrain. */ /** The underlying height generator, used for placing the structures on top of the terrain. */
cTerrainHeightGen & m_HeightGen; cTerrainHeightGen & m_HeightGen;
@ -149,7 +160,7 @@ protected:
BLOCKTYPE m_RoadBlock; BLOCKTYPE m_RoadBlock;
// cGrdStructGen::cStructure overrides: // cGridStructGen::cStructure overrides:
virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override
{ {
// Iterate over all items // Iterate over all items
@ -211,6 +222,49 @@ protected:
} }
} }
} }
// cPiecePool overrides:
virtual cPieces GetPiecesWithConnector(int a_ConnectorType)
{
return m_Prefabs.GetPiecesWithConnector(a_ConnectorType);
}
virtual cPieces GetStartingPieces(void)
{
return m_Prefabs.GetStartingPieces();
}
virtual int GetPieceWeight(
const cPlacedPiece & a_PlacedPiece,
const cPiece::cConnector & a_ExistingConnector,
const cPiece & a_NewPiece
) override
{
// Check against the density:
if (a_ExistingConnector.m_Type == 1)
{
const Vector3i & Coords = a_PlacedPiece.GetRotatedConnector(a_ExistingConnector).m_Pos;
int rnd = (m_Noise.IntNoise3DInt(Coords.x, Coords.y, Coords.z) / 7) % 100;
if (rnd > m_Density)
{
return 0;
}
}
// Density check passed, relay to m_Prefabs:
return m_Prefabs.GetPieceWeight(a_PlacedPiece, a_ExistingConnector, a_NewPiece);
}
virtual void PiecePlaced(const cPiece & a_Piece) override
{
m_Prefabs.PiecePlaced(a_Piece);
}
virtual void Reset(void) override
{
m_Prefabs.Reset();
}
} ; } ;
@ -233,10 +287,13 @@ static cVillagePiecePool g_PlainsVillage(g_PlainsVillagePrefabs, g_PlainsVillage
cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) : cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) :
super(a_Seed, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 100), super(a_Seed, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 100),
m_Noise(a_Seed + 1000),
m_MaxDepth(a_MaxDepth), m_MaxDepth(a_MaxDepth),
m_MaxSize(a_MaxSize), m_MaxSize(a_MaxSize),
m_MinDensity(a_MinDensity),
m_MaxDensity(a_MaxDensity),
m_BiomeGen(a_BiomeGen), m_BiomeGen(a_BiomeGen),
m_HeightGen(a_HeightGen) m_HeightGen(a_HeightGen)
{ {
@ -258,7 +315,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_
// If just one is not, no village is created, because it's likely that an unfriendly biome is too close // If just one is not, no village is created, because it's likely that an unfriendly biome is too close
cVillagePiecePool * VillagePrefabs = NULL; cVillagePiecePool * VillagePrefabs = NULL;
BLOCKTYPE RoadBlock = E_BLOCK_GRAVEL; BLOCKTYPE RoadBlock = E_BLOCK_GRAVEL;
int rnd = (a_OriginX + 21 * a_OriginZ + 985) / 11; int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 11;
for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++) for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++)
{ {
switch (Biomes[i]) switch (Biomes[i])
@ -288,12 +345,23 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_
} // switch (Biomes[i]) } // switch (Biomes[i])
} // for i - Biomes[] } // for i - Biomes[]
// Choose density for the village, random between m_MinDensity and m_MaxDensity:
int Density;
if (m_MaxDensity > m_MinDensity)
{
Density = m_MinDensity + rnd % (m_MaxDensity - m_MinDensity);
}
else
{
Density = m_MinDensity;
}
// Create a village based on the chosen prefabs: // Create a village based on the chosen prefabs:
if (VillagePrefabs == NULL) if (VillagePrefabs == NULL)
{ {
return cStructurePtr(); return cStructurePtr();
} }
return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, *VillagePrefabs, m_HeightGen, RoadBlock)); return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, Density, *VillagePrefabs, m_HeightGen, RoadBlock));
} }

View File

@ -21,16 +21,25 @@ class cVillageGen :
{ {
typedef cGridStructGen super; typedef cGridStructGen super;
public: public:
cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen); cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen);
protected: protected:
class cVillage; // fwd: VillageGen.cpp class cVillage; // fwd: VillageGen.cpp
/** The noise used for generating random numbers */
cNoise m_Noise;
/** Maximum depth of the generator tree*/ /** Maximum depth of the generator tree*/
int m_MaxDepth; int m_MaxDepth;
/** Maximum size, in X/Z blocks, of the village (radius from the origin) */ /** Maximum size, in X/Z blocks, of the village (radius from the origin) */
int m_MaxSize; int m_MaxSize;
/** Minimum density - percentage of allowed house connections. Range [0, 100] */
int m_MinDensity;
/** Maximum density - percentage of allowed house connections. Range [0, 100] */
int m_MaxDensity;
/** The underlying biome generator that defines whether the village is created or not */ /** The underlying biome generator that defines whether the village is created or not */
cBiomeGen & m_BiomeGen; cBiomeGen & m_BiomeGen;