From 6aa7df367f8db7506a8a5ab853c26e3c9fd60253 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 22 May 2014 21:47:56 +0200 Subject: Villages have min and max density setting. Also made roads use 3+9 scheme, instead of 3+5, for the house connectors. Fixes #1020. --- src/Generating/ComposableGenerator.cpp | 10 ++-- src/Generating/PieceGenerator.cpp | 9 ++++ src/Generating/PieceGenerator.h | 5 ++ src/Generating/VillageGen.cpp | 92 +++++++++++++++++++++++++++++----- src/Generating/VillageGen.h | 11 +++- 5 files changed, 110 insertions(+), 17 deletions(-) (limited to 'src/Generating') diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index f264599c9..4dd626ed4 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -408,10 +408,12 @@ 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 MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128); - m_FinishGens.push_back(new cVillageGen(Seed, GridSize, MaxDepth, MaxSize, *m_BiomeGen, *m_HeightGen)); + int GridSize = a_IniFile.GetValueSetI("Generator", "VillageGridSize", 384); + int MaxDepth = a_IniFile.GetValueSetI("Generator", "VillageMaxDepth", 2); + int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128); + 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) { diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp index c12559d3f..7d478f1a1 100644 --- a/src/Generating/PieceGenerator.cpp +++ b/src/Generating/PieceGenerator.cpp @@ -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: diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h index 643ca58b6..e396643a9 100644 --- a/src/Generating/PieceGenerator.h +++ b/src/Generating/PieceGenerator.h @@ -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; diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index a899d5837..bcce62af5 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -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)); } diff --git a/src/Generating/VillageGen.h b/src/Generating/VillageGen.h index c6f8f024a..5faaae8a6 100644 --- a/src/Generating/VillageGen.h +++ b/src/Generating/VillageGen.h @@ -21,16 +21,25 @@ 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; -- cgit v1.2.3