From f5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 15 May 2014 00:14:06 +0200 Subject: VillageGen rewritten using BFSPieceGenerator. Piece composition is not good yet, the buildings aren't height-adjusted and the road pieces will need special processing. This is mainly for adjusting the per-piece params. --- src/Generating/VillageGen.cpp | 196 ++++++++++++++++++++---------------------- 1 file changed, 91 insertions(+), 105 deletions(-) (limited to 'src/Generating/VillageGen.cpp') diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index 3d89d7aa2..3358bc531 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -7,6 +7,7 @@ #include "VillageGen.h" #include "Prefabs/PlainsVillagePrefabs.h" #include "Prefabs/SandVillagePrefabs.h" +#include "PieceGenerator.h" @@ -19,18 +20,79 @@ the grid's cells. Each cell checks the biomes in an entire chunk around it, only biomes are village-friendly. If yes, the entire village structure is built for that cell. If not, the cell is left village-less. -A village is generated starting by its well. The well is placed in the grid's origin point. Then a set of -random lengths roads is generated - 4 roads going from the well, then at the end of each road another set of -roads, crossing them perpendicular, then at the end of those another set, up to a set maximum branching -depth. The roads are placed in a T or L shape, with the old road being the center stem of the T. Roads avoid -crossing each other and going further away from the well than the maximum block size of the village. -Finally, houses are places along the roads, avoiding collisions with already-existing items. +A village is generated using the regular BFS piece generator. The well piece is used as the starting piece, +the roads and houses are then used as the following pieces. Only the houses are read from the prefabs, +though, the roads are generated by code and their content is ignored. A special subclass of the cPiecePool +class is used, so that the roads connect to each other and to the well only in predefined manners. -When the village is about to be drawn into a chunk, it queries the heights for each item intersecting the -chunk. The prefabs are shifted so that their pivot points lie on the surface, and the roads are drawn +The well has connectors of type "1". The houses have connectors of type "-1". The roads have connectors of +both types, type "-1" at the far ends and type "1" on the long edges. + +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. */ +class cVillagePiecePool : + public cPrefabPiecePool +{ + typedef cPrefabPiecePool super; +public: + cVillagePiecePool( + const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs, + const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs + ) : + super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs) + { + // Add the road piece: + cBlockArea BA; + BA.Create(5, 1, 3, cBlockArea::baTypes | cBlockArea::baMetas); + BA.Fill(cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_GRAVEL, 0); + cPrefab * RoadPiece = new cPrefab(BA, 7); + RoadPiece->AddConnector(0, 0, 1, BLOCK_FACE_XM, -1); + RoadPiece->AddConnector(4, 0, 1, BLOCK_FACE_XP, -1); + RoadPiece->AddConnector(4, 0, 1, BLOCK_FACE_XP, 1); + RoadPiece->AddConnector(1, 0, 0, BLOCK_FACE_ZM, 1); + RoadPiece->AddConnector(3, 0, 0, BLOCK_FACE_ZM, 1); + RoadPiece->AddConnector(1, 0, 2, BLOCK_FACE_ZP, 1); + RoadPiece->AddConnector(3, 0, 2, BLOCK_FACE_ZP, 1); + RoadPiece->SetAddWeightIfSame(10000); + m_AllPieces.push_back(RoadPiece); + m_PiecesByConnector[-1].push_back(RoadPiece); + m_PiecesByConnector[1].push_back(RoadPiece); + } + + + // cPrefabPiecePool overrides: + virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override + { + // Only roads are allowed to connect to the well: + if ((a_PlacedPiece.GetDepth() == 0) && (a_NewPiece.GetSize().y != 1)) + { + return 0; + } + + // Roads cannot branch T-wise: + if ( + (a_PlacedPiece.GetPiece().GetSize().y == 1) && // Connecting to a road + ( + (a_ExistingConnector.m_Direction == BLOCK_FACE_ZP) || + (a_ExistingConnector.m_Direction == BLOCK_FACE_ZM) + ) && // Through the long-edge connector + (a_NewPiece.GetSize().y == 1) // And the new piece is a road + ) + { + return 0; + } + + return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector); + } +} ; + + + + + class cVillageGen::cVillage : public cGridStructGen::cStructure { @@ -53,44 +115,11 @@ public: m_Prefabs(a_Prefabs), m_HeightGen(a_HeightGen) { - PlaceWell(); - BuildRoads(a_MaxRoadDepth); - PlaceHouses(); + cBFSPieceGenerator pg(m_Prefabs, a_Seed); + pg.PlacePieces(a_OriginX, 10, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces); } protected: - class cItem - { - public: - /* The position of the item, X/Z-wise: */ - int m_MinX, m_MaxX, m_MinZ, m_MaxZ; - - /** The prefab to use. If NULL, this is a road. */ - cPrefab * m_Prefab; - - /** Number of rotations that should be applied to the prefab. */ - int m_NumRotations; - - /* The bottom of the prefab. Only valid if the item is a prefab, not valid for roads. */ - int m_BaseY; - - /** Creates a new item with the specified parameters. - m_BaseY is set to -1 and will be adjusted later on when drawing. */ - cItem(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, cPrefab * a_Prefab, int a_NumRotations) : - m_MinX(a_MinX), - m_MaxX(a_MaxX), - m_MinZ(a_MinZ), - m_MaxZ(a_MaxZ), - m_Prefab(a_Prefab), - m_NumRotations(a_NumRotations), - m_BaseY(-1) - { - } - } ; - typedef SharedPtr cItemPtr; - typedef std::vector cItemPtrs; - - /** Seed for the random functions */ int m_Seed; @@ -109,61 +138,8 @@ protected: /** The underlying height generator, used for placing the structures on top of the terrain. */ cTerrainHeightGen & m_HeightGen; - /** The items that are generated in the village (houses, roads). */ - cItemPtrs m_Items; - - - /** Places the well at the center of the village */ - void PlaceWell(void) - { - // Pick a prefab from the starting pieces: - cPieces StartingPieces = ((cPiecePool &)m_Prefabs).GetStartingPieces(); - ASSERT(!StartingPieces.empty()); - int TotalWeight = 0; - for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr) - { - TotalWeight += ((const cPrefab *)(*itr))->GetDefaultWeight(); - } - ASSERT(TotalWeight > 0); - int rnd = (m_Noise.IntNoise2DInt(m_OriginX, m_OriginZ) / 7) % TotalWeight; - cPiece * WellPiece = StartingPieces[0]; - for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr) - { - rnd -= ((const cPrefab *)(*itr))->GetDefaultWeight(); - if (rnd <= 0) - { - WellPiece = *itr; - break; - } - } - ASSERT(WellPiece != NULL); - - // Pick a rotation: - // TODO - int NumRotations = 0; - Vector3i Size = WellPiece->GetSize(); - - // Put the well in the placed items array: - m_Items.push_back(cItemPtr(new cItem(m_OriginX, m_OriginX + Size.x, m_OriginZ, m_OriginZ + Size.z, (cPrefab *)WellPiece, NumRotations))); - } - - - /** Places the roads going from the well outwards. */ - void BuildRoads(int a_MaxRoadDepth) - { - /* - ASSERT(m_Items.size() == 1); - const cItem & Well = *m_Items[0]; - */ - // TODO - } - - - /** Places houses along the roads. */ - void PlaceHouses(void) - { - // TODO - } + /** The village pieces, placed by the generator. */ + cPlacedPieces m_Pieces; // cGrdStructGen::cStructure overrides: @@ -173,6 +149,11 @@ protected: // Iterate over all items // Each intersecting prefab is placed on ground (if not already placed), then drawn // Each intersecting road is drawn by replacing top soil blocks with gravel / sandstone blocks + for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr) + { + const cPrefab & Prefab = (const cPrefab &)((*itr)->GetPiece()); + Prefab.Draw(a_Chunk, *itr); + } // for itr - m_PlacedPieces[] } } ; @@ -183,15 +164,20 @@ protected: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cVillageGen: -cPrefabPiecePool cVillageGen::m_SandVillage (g_SandVillagePrefabs, g_SandVillagePrefabsCount, g_SandVillageStartingPrefabs, g_SandVillageStartingPrefabsCount); -cPrefabPiecePool cVillageGen::m_PlainsVillage(g_PlainsVillagePrefabs, g_PlainsVillagePrefabsCount, g_PlainsVillageStartingPrefabs, g_PlainsVillageStartingPrefabsCount); +/** The prefabs for the sand village. */ +static cVillagePiecePool g_SandVillage (g_SandVillagePrefabs, g_SandVillagePrefabsCount, g_SandVillageStartingPrefabs, g_SandVillageStartingPrefabsCount); + +/** The prefabs for the plains village. */ +static cVillagePiecePool g_PlainsVillage(g_PlainsVillagePrefabs, g_PlainsVillagePrefabsCount, g_PlainsVillageStartingPrefabs, g_PlainsVillageStartingPrefabsCount); -cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxRoadDepth, int a_MaxSize, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) : +cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) : super(a_Seed, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 100), + m_MaxDepth(a_MaxDepth), + m_MaxSize(a_MaxSize), m_BiomeGen(a_BiomeGen), m_HeightGen(a_HeightGen) { @@ -211,7 +197,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_ // Check if all the biomes are village-friendly: // If just one is not, no village is created, because it's likely that an unfriendly biome is too close - cPrefabPiecePool * VillagePrefabs = NULL; + cVillagePiecePool * VillagePrefabs = NULL; for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++) { switch (Biomes[i]) @@ -220,7 +206,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_ case biDesertM: { // These biomes allow sand villages - VillagePrefabs = &m_SandVillage; + VillagePrefabs = &g_SandVillage; break; } case biPlains: @@ -229,7 +215,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_ case biSunflowerPlains: { // These biomes allow plains-style villages - VillagePrefabs = &m_PlainsVillage; + VillagePrefabs = &g_PlainsVillage; break; } default: @@ -245,7 +231,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_ { return cStructurePtr(); } - return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxRoadDepth, m_MaxSize, *VillagePrefabs, m_HeightGen)); + return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, *VillagePrefabs, m_HeightGen)); } -- cgit v1.2.3