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:
parent
ebb1ef237a
commit
6aa7df367f
@ -409,9 +409,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
else if (NoCaseCompare(*itr, "Villages") == 0)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
|
@ -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:
|
||||
|
||||
|
@ -110,6 +110,7 @@ public:
|
||||
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.
|
||||
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.
|
||||
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. */
|
||||
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:
|
||||
const cPlacedPiece * m_Parent;
|
||||
const cPiece * m_Piece;
|
||||
|
@ -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.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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 :
|
||||
@ -46,7 +51,7 @@ public:
|
||||
super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs)
|
||||
{
|
||||
// Add the road pieces:
|
||||
for (int len = 19; len < 60; len += 8)
|
||||
for (int len = 27; len < 60; len += 12)
|
||||
{
|
||||
cBlockArea BA;
|
||||
BA.Create(len, 1, 3, cBlockArea::baTypes | cBlockArea::baMetas);
|
||||
@ -56,14 +61,14 @@ public:
|
||||
RoadPiece->AddConnector(len - 1, 0, 1, BLOCK_FACE_XP, -2);
|
||||
|
||||
// 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, 2, BLOCK_FACE_ZP, 2);
|
||||
}
|
||||
|
||||
// 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, 2, BLOCK_FACE_ZP, 1);
|
||||
@ -94,7 +99,8 @@ public:
|
||||
|
||||
|
||||
class cVillageGen::cVillage :
|
||||
public cGridStructGen::cStructure
|
||||
public cGridStructGen::cStructure,
|
||||
protected cPiecePool
|
||||
{
|
||||
typedef cGridStructGen::cStructure super;
|
||||
|
||||
@ -104,7 +110,8 @@ public:
|
||||
int a_OriginX, int a_OriginZ,
|
||||
int a_MaxRoadDepth,
|
||||
int a_MaxSize,
|
||||
cPrefabPiecePool & a_Prefabs,
|
||||
int a_Density,
|
||||
cPiecePool & a_Prefabs,
|
||||
cTerrainHeightGen & a_HeightGen,
|
||||
BLOCKTYPE a_RoadBlock
|
||||
) :
|
||||
@ -112,12 +119,13 @@ public:
|
||||
m_Seed(a_Seed),
|
||||
m_Noise(a_Seed),
|
||||
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_Prefabs(a_Prefabs),
|
||||
m_HeightGen(a_HeightGen),
|
||||
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
|
||||
// Piece has negative Y coord -> hasn't been height-adjusted yet
|
||||
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) */
|
||||
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. */
|
||||
cCuboid m_Borders;
|
||||
|
||||
/** 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. */
|
||||
cTerrainHeightGen & m_HeightGen;
|
||||
@ -149,7 +160,7 @@ protected:
|
||||
BLOCKTYPE m_RoadBlock;
|
||||
|
||||
|
||||
// cGrdStructGen::cStructure overrides:
|
||||
// cGridStructGen::cStructure overrides:
|
||||
virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override
|
||||
{
|
||||
// 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),
|
||||
m_Noise(a_Seed + 1000),
|
||||
m_MaxDepth(a_MaxDepth),
|
||||
m_MaxSize(a_MaxSize),
|
||||
m_MinDensity(a_MinDensity),
|
||||
m_MaxDensity(a_MaxDensity),
|
||||
m_BiomeGen(a_BiomeGen),
|
||||
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
|
||||
cVillagePiecePool * VillagePrefabs = NULL;
|
||||
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++)
|
||||
{
|
||||
switch (Biomes[i])
|
||||
@ -288,12 +345,23 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_
|
||||
} // switch (Biomes[i])
|
||||
} // 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:
|
||||
if (VillagePrefabs == NULL)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,17 +21,26 @@ class cVillageGen :
|
||||
{
|
||||
typedef cGridStructGen super;
|
||||
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:
|
||||
class cVillage; // fwd: VillageGen.cpp
|
||||
|
||||
/** The noise used for generating random numbers */
|
||||
cNoise m_Noise;
|
||||
|
||||
/** Maximum depth of the generator tree*/
|
||||
int m_MaxDepth;
|
||||
|
||||
/** Maximum size, in X/Z blocks, of the village (radius from the origin) */
|
||||
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 */
|
||||
cBiomeGen & m_BiomeGen;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user