f5fdbdaf29
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.
240 lines
7.3 KiB
C++
240 lines
7.3 KiB
C++
|
|
// VillageGen.cpp
|
|
|
|
// Implements the cVillageGen class representing the village generator
|
|
|
|
#include "Globals.h"
|
|
#include "VillageGen.h"
|
|
#include "Prefabs/PlainsVillagePrefabs.h"
|
|
#include "Prefabs/SandVillagePrefabs.h"
|
|
#include "PieceGenerator.h"
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
How village generating works:
|
|
By descending from a cGridStructGen, a semi-random grid is generated. A village may be generated for each of
|
|
the grid's cells. Each cell checks the biomes in an entire chunk around it, only generating a village if all
|
|
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 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.
|
|
|
|
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
|
|
{
|
|
typedef cGridStructGen::cStructure super;
|
|
|
|
public:
|
|
cVillage(
|
|
int a_Seed,
|
|
int a_OriginX, int a_OriginZ,
|
|
int a_MaxRoadDepth,
|
|
int a_MaxSize,
|
|
cPrefabPiecePool & a_Prefabs,
|
|
cTerrainHeightGen & a_HeightGen
|
|
) :
|
|
super(a_OriginX, a_OriginZ),
|
|
m_Seed(a_Seed),
|
|
m_Noise(a_Seed),
|
|
m_MaxSize(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_HeightGen(a_HeightGen)
|
|
{
|
|
cBFSPieceGenerator pg(m_Prefabs, a_Seed);
|
|
pg.PlacePieces(a_OriginX, 10, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces);
|
|
}
|
|
|
|
protected:
|
|
/** Seed for the random functions */
|
|
int m_Seed;
|
|
|
|
/** The noise used as a pseudo-random generator */
|
|
cNoise m_Noise;
|
|
|
|
/** Maximum size, in X/Z blocks, of the village (radius from the origin) */
|
|
int m_MaxSize;
|
|
|
|
/** Borders of the vilalge - no item may reach out of this cuboid. */
|
|
cCuboid m_Borders;
|
|
|
|
/** Prefabs to use for buildings */
|
|
cPrefabPiecePool & m_Prefabs;
|
|
|
|
/** The underlying height generator, used for placing the structures on top of the terrain. */
|
|
cTerrainHeightGen & m_HeightGen;
|
|
|
|
/** The village pieces, placed by the generator. */
|
|
cPlacedPieces m_Pieces;
|
|
|
|
|
|
// cGrdStructGen::cStructure overrides:
|
|
virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override
|
|
{
|
|
// TODO
|
|
// 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[]
|
|
}
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// cVillageGen:
|
|
|
|
/** 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_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)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_OriginZ)
|
|
{
|
|
// Generate the biomes for the chunk surrounding the origin:
|
|
int ChunkX, ChunkZ;
|
|
cChunkDef::BlockToChunk(a_OriginX, a_OriginZ, ChunkX, ChunkZ);
|
|
cChunkDef::BiomeMap Biomes;
|
|
m_BiomeGen.GenBiomes(ChunkX, ChunkZ, Biomes);
|
|
|
|
// 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
|
|
cVillagePiecePool * VillagePrefabs = NULL;
|
|
for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++)
|
|
{
|
|
switch (Biomes[i])
|
|
{
|
|
case biDesert:
|
|
case biDesertM:
|
|
{
|
|
// These biomes allow sand villages
|
|
VillagePrefabs = &g_SandVillage;
|
|
break;
|
|
}
|
|
case biPlains:
|
|
case biSavanna:
|
|
case biSavannaM:
|
|
case biSunflowerPlains:
|
|
{
|
|
// These biomes allow plains-style villages
|
|
VillagePrefabs = &g_PlainsVillage;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
// Village-unfriendly biome, bail out with zero structure:
|
|
return cStructurePtr();
|
|
}
|
|
} // switch (Biomes[i])
|
|
} // for i - Biomes[]
|
|
|
|
// 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));
|
|
}
|
|
|
|
|
|
|
|
|