From fbf5cf7aa61a48f916afd81ac7e282eac8d50e6f Mon Sep 17 00:00:00 2001 From: Cocosushi6 Date: Thu, 3 May 2018 20:25:08 +0200 Subject: [PATCH] Generate cacti and sugarcane with different heights (#4137) When generating foliage, create cacti with height in the interval [1; MaxCactusHeight] and sugarcane with height in [1; MaxSugarcaneHeight] (with MaxCactusHeight and MaxSugarcaneHeight declared in world.ini) Fixes #4135 --- CONTRIBUTORS | 1 + src/Generating/ComposableGenerator.cpp | 4 +- src/Generating/FinishGen.cpp | 111 ++++++++++++++++++------- src/Generating/FinishGen.h | 18 +++- 4 files changed, 101 insertions(+), 33 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 2e2103f05..35d8496b4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -13,6 +13,7 @@ beeduck bibo38 birkett (Anthony Birkett) Bond_009 +Cocosushi6 derouinw Diusrex Duralex diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index e964bca46..c73ecf6cc 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -525,7 +525,9 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(finisher, "SprinkleFoliage") == 0) { - m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSprinkleFoliage(Seed))); + int MaxCactusHeight = a_IniFile.GetValueI("Plants", "MaxCactusHeight", 3); + int MaxSugarcaneHeight = a_IniFile.GetValueI("Plants", "MaxSugarcaneHeight", 3); + m_FinishGens.push_back(std::make_shared(Seed, MaxCactusHeight, MaxSugarcaneHeight)); } else if (NoCaseCompare(finisher, "TallGrass") == 0) { diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 8c54be0d0..ec5c0c144 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -671,24 +671,66 @@ void cFinishGenVines::GenFinish(cChunkDesc & a_ChunkDesc) //////////////////////////////////////////////////////////////////////////////// // cFinishGenSprinkleFoliage: -bool cFinishGenSprinkleFoliage::TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ) +bool cFinishGenSprinkleFoliage::TryAddCactus(cChunkDesc & a_ChunkDesc, int a_RelX, HEIGHTTYPE & a_RelY, int a_RelZ) { + if (!IsDesertVariant(a_ChunkDesc.GetBiome(a_RelX, a_RelZ))) + { + return false; + } + + int CactusHeight = 1 + (m_Noise.IntNoise2DInt(a_RelX, a_RelZ) % m_MaxCactusHeight); + + // We'll be doing comparison with blocks above, so the coords should be 1 block away from chunk top + if (a_RelY + CactusHeight >= cChunkDef::Height - 1) + { + CactusHeight = cChunkDef::Height - a_RelY - 1; + } + // We'll be doing comparison to neighbors, so require the coords to be 1 block away from the chunk edges: if ( - (a_RelX < 1) || (a_RelX >= cChunkDef::Width - 1) || - (a_RelY < 1) || (a_RelY >= cChunkDef::Height - 2) || - (a_RelZ < 1) || (a_RelZ >= cChunkDef::Width - 1) + (a_RelX < 1) || (a_RelX >= cChunkDef::Width - 1) || + (a_RelZ < 1) || (a_RelZ >= cChunkDef::Width - 1) ) { return false; } - // Only allow dirt, grass or sand below sugarcane: + for (int i = 0; i < CactusHeight; i++) + { + const bool cactusExists = i != 0; + + const int y = a_RelY + 1; + if ( + cBlockInfo::IsSolid(a_ChunkDesc.GetBlockType(a_RelX + 1, y, a_RelZ)) || + cBlockInfo::IsSolid(a_ChunkDesc.GetBlockType(a_RelX - 1, y, a_RelZ)) || + cBlockInfo::IsSolid(a_ChunkDesc.GetBlockType(a_RelX, y, a_RelZ + 1)) || + cBlockInfo::IsSolid(a_ChunkDesc.GetBlockType(a_RelX, y, a_RelZ - 1)) + ) + { + return cactusExists; + } + + // All conditions are met, we can place a cactus here + a_ChunkDesc.SetBlockType(a_RelX, ++a_RelY, a_RelZ, E_BLOCK_CACTUS); + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// cFinishGenSprinkleFoliage: + +bool cFinishGenSprinkleFoliage::TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_RelX, HEIGHTTYPE & a_RelY, int a_RelZ) +{ + int SugarcaneHeight = 1 + (m_Noise.IntNoise2DInt(a_RelX, a_RelZ) % m_MaxSugarcaneHeight); + + // Only allow dirt, grass, sand and sugarcane below sugarcane: switch (a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ)) { case E_BLOCK_DIRT: case E_BLOCK_GRASS: case E_BLOCK_SAND: + case E_BLOCK_SUGARCANE: { break; } @@ -698,19 +740,39 @@ bool cFinishGenSprinkleFoliage::TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_ } } - // Water is required next to the block below the sugarcane: + // We'll be doing comparison with blocks above, so the coords should be 1 block away from chunk top + if (a_RelY + SugarcaneHeight >= cChunkDef::Height - 1) + { + SugarcaneHeight = cChunkDef::Height - a_RelY - 1; + } + + // We'll be doing comparison to neighbors, so require the coords to be 1 block away from the chunk edges: if ( - !IsWater(a_ChunkDesc.GetBlockType(a_RelX - 1, a_RelY, a_RelZ)) && - !IsWater(a_ChunkDesc.GetBlockType(a_RelX + 1, a_RelY, a_RelZ)) && - !IsWater(a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ - 1)) && - !IsWater(a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ + 1)) + (a_RelX < 1) || (a_RelX >= cChunkDef::Width - 1) || + (a_RelZ < 1) || (a_RelZ >= cChunkDef::Width - 1) ) { return false; } - // All conditions met, place a sugarcane here: - a_ChunkDesc.SetBlockType(a_RelX, a_RelY + 1, a_RelZ, E_BLOCK_SUGARCANE); + // Water is required next to the block below the sugarcane (if the block below isn't sugarcane already) + if ( + !IsWater(a_ChunkDesc.GetBlockType(a_RelX - 1, a_RelY, a_RelZ)) && + !IsWater(a_ChunkDesc.GetBlockType(a_RelX + 1, a_RelY, a_RelZ)) && + !IsWater(a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ - 1)) && + !IsWater(a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ + 1)) && + a_ChunkDesc.GetBlockType(a_RelX, a_RelY, a_RelZ) != E_BLOCK_SUGARCANE + ) + { + return false; + } + + for (int i = 0; i < SugarcaneHeight; i++) + { + // All conditions met, place a sugarcane here + a_ChunkDesc.SetBlockType(a_RelX, ++a_RelY, a_RelZ, E_BLOCK_SUGARCANE); + } + return true; } @@ -778,7 +840,7 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc) } else if (TryAddSugarcane(a_ChunkDesc, x, Top, z)) { - ++Top; + // Checks and block placing are handled in the TryAddSugarcane method } else if ((val1 > 0.5) && (val2 < -0.5)) { @@ -789,29 +851,22 @@ void cFinishGenSprinkleFoliage::GenFinish(cChunkDesc & a_ChunkDesc) case E_BLOCK_SAND: { - int y = Top + 1; - if ( - (x > 0) && (x < cChunkDef::Width - 1) && - (z > 0) && (z < cChunkDef::Width - 1) && - (val1 + val2 > 0.5f) && - (a_ChunkDesc.GetBlockType(x + 1, y, z) == E_BLOCK_AIR) && - (a_ChunkDesc.GetBlockType(x - 1, y, z) == E_BLOCK_AIR) && - (a_ChunkDesc.GetBlockType(x, y, z + 1) == E_BLOCK_AIR) && - (a_ChunkDesc.GetBlockType(x, y, z - 1) == E_BLOCK_AIR) && - IsDesertVariant(a_ChunkDesc.GetBiome(x, z)) - ) + if (val1 + val2 > 0.5f) { - a_ChunkDesc.SetBlockType(x, ++Top, z, E_BLOCK_CACTUS); + if (!TryAddCactus(a_ChunkDesc, x, Top, z)) + { + TryAddSugarcane(a_ChunkDesc, x, Top, z); + } } - else if (TryAddSugarcane(a_ChunkDesc, x, Top, z)) + else { - ++Top; + TryAddSugarcane(a_ChunkDesc, x, Top, z); } break; } } // switch (TopBlock) a_ChunkDesc.SetHeight(x, z, Top); - } // for y + } // for x } // for z } diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index 0138c84bc..b6edce84f 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -260,14 +260,24 @@ class cFinishGenSprinkleFoliage : public cFinishGen { public: - cFinishGenSprinkleFoliage(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {} - + cFinishGenSprinkleFoliage(int a_Seed, int a_MaxCactusHeight, int a_MaxSugarcaneHeight): + m_Noise(a_Seed), + m_Seed(a_Seed), + m_MaxCactusHeight(a_MaxCactusHeight), + m_MaxSugarcaneHeight(a_MaxSugarcaneHeight) + { + } protected: cNoise m_Noise; int m_Seed; + int m_MaxCactusHeight; + int m_MaxSugarcaneHeight; - /** Tries to place sugarcane at the coords specified, returns true if successful */ - bool TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ); + /** Tries to place sugarcane at the coords specified, returns true if successful, updates the top variable (hence the & a_RefY) */ + bool TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_RelX, HEIGHTTYPE & a_RelY, int a_RelZ); + + /** Tries to place cactus at the coords specified, returns true if successful, updates the top variable (hence the & a_RefY) */ + bool TryAddCactus(cChunkDesc & a_ChunkDesc, int a_RelX, HEIGHTTYPE & a_RelY, int a_RelZ); // Returns true is the specified biome is a desert or its variant static bool IsDesertVariant(EMCSBiome a_biome);