diff --git a/src/Chunk.cpp b/src/Chunk.cpp index c65c043da..06d5eb319 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1105,6 +1105,37 @@ int cChunk::GrowCactus(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks) +bool cChunk::GrowTallGrass(int a_RelX, int a_RelY, int a_RelZ) +{ + if (a_RelY > (cChunkDef::Height - 2)) + { + return false; + } + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + if (!UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta)) + { + return false; + } + if (BlockType != E_BLOCK_TALL_GRASS) + { + return false; + } + NIBBLETYPE LargeFlowerMeta; + switch (BlockMeta) + { + case E_META_TALL_GRASS_GRASS: LargeFlowerMeta = E_META_BIG_FLOWER_DOUBLE_TALL_GRASS; break; + case E_META_TALL_GRASS_FERN: LargeFlowerMeta = E_META_BIG_FLOWER_LARGE_FERN; break; + default: return false; + } + return UnboundedRelFastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_BIG_FLOWER, LargeFlowerMeta) && + UnboundedRelFastSetBlock(a_RelX, a_RelY + 1, a_RelZ, E_BLOCK_BIG_FLOWER, 8); +} + + + + + bool cChunk::UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const { if (!cChunkDef::IsValidHeight(a_RelY)) diff --git a/src/Chunk.h b/src/Chunk.h index f8bd9075d..162c8de96 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -586,6 +586,9 @@ private: /** Grows cactus by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking); returns the amount of blocks the cactus grew inside this call */ int GrowCactus (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks); + /** Grows a tall grass present at the block specified to a two tall grass; returns true if the grass grew */ + bool GrowTallGrass (int a_RelX, int a_RelY, int a_RelZ); + /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem); returns true if the pumpkin or melon sucessfully grew */ bool GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, MTRand & a_Random); diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index be22244ad..55cabaa67 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -2651,6 +2651,24 @@ int cChunkMap::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlo +bool cChunkMap::GrowTallGrass(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + int ChunkX, ChunkZ; + cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); + + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); + if (Chunk != nullptr) + { + return Chunk->GrowTallGrass(a_BlockX, a_BlockY, a_BlockZ); + } + return 0; +} + + + + + void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) { int ChunkX, ChunkZ; diff --git a/src/ChunkMap.h b/src/ChunkMap.h index b481e3c9b..8a604ac09 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -369,6 +369,9 @@ public: /** Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config; returns the amount of blocks the cactus grew inside this call */ int GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); + /** Grows a tall grass present at the block specified to a two tall grass; returns true if the grass grew */ + bool GrowTallGrass(int a_BlockX, int a_BlockY, int a_BlockZ); + /** Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call */ void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); diff --git a/src/World.cpp b/src/World.cpp index 55079250c..a8225693f 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -187,6 +187,8 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_IsPumpkinBonemealable(true), m_IsSaplingBonemealable(true), m_IsSugarcaneBonemealable(false), + m_IsBigFlowerBonemealable(true), + m_IsTallGrassBonemealable(true), m_bCommandBlocksEnabled(true), m_bUseChatPrefixes(false), m_TNTShrapnelLevel(slNone), @@ -471,6 +473,8 @@ void cWorld::Start(void) m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false); m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true); m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false); + m_IsBigFlowerBonemealable = IniFile.GetValueSetB("Plants", "IsBigFlowerBonemealable", true); + m_IsTallGrassBonemealable = IniFile.GetValueSetB("Plants", "IsTallGrassBonemealable", true); m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true); m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true); int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", static_cast(slAll)); @@ -1778,8 +1782,6 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy BlockMeta = std::min(BlockMeta, static_cast(7)); } FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); - BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); - return true; } else { @@ -1787,8 +1789,13 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy { return false; } - return GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, BlockType); + if (!GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, BlockType)) + { + return false; + } } + BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); + return true; } case E_BLOCK_POTATOES: @@ -1830,8 +1837,6 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy BlockMeta = std::min(BlockMeta, static_cast(7)); } FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); - BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); - return true; } else { @@ -1839,8 +1844,13 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy { return false; } - return GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, BlockType); + if (!GrowMelonPumpkin(a_BlockX, a_BlockY, a_BlockZ, BlockType)) + { + return false; + } } + BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); + return true; } case E_BLOCK_SAPLING: @@ -1865,15 +1875,13 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy } FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, static_cast(GrowState << 3 | TypeMeta)); - BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); } else if (random.NextInt(99) < 45) { - GrowTreeFromSapling(a_BlockX, a_BlockY, a_BlockZ, BlockMeta); - return true; } - return false; + BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); + return true; } case E_BLOCK_GRASS: @@ -1923,7 +1931,12 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy { return false; } - return m_ChunkMap->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, 1) != 0; + if (m_ChunkMap->GrowSugarcane(a_BlockX, a_BlockY, a_BlockZ, 1) == 0) + { + return false; + } + BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); + return true; } case E_BLOCK_CACTUS: @@ -1932,8 +1945,58 @@ bool cWorld::GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsBy { return false; } - return m_ChunkMap->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, 1) != 0; + if (m_ChunkMap->GrowCactus(a_BlockX, a_BlockY, a_BlockZ, 1) == 0) + { + return false; + } + BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); + return true; } + + case E_BLOCK_TALL_GRASS: + { + if (a_IsByBonemeal && !m_IsTallGrassBonemealable) + { + return false; + } + if (!m_ChunkMap->GrowTallGrass(a_BlockX, a_BlockY, a_BlockZ)) + { + return false; + } + BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); + return true; + } + + case E_BLOCK_BIG_FLOWER: + { + if (a_IsByBonemeal && !m_IsBigFlowerBonemealable) + { + return false; + } + if (BlockMeta & 8) // the upper flower block does not save the type of the flower + { + GetBlockTypeMeta(a_BlockX, a_BlockY - 1, a_BlockZ, BlockType, BlockMeta); + if (BlockType != E_BLOCK_BIG_FLOWER) + { + return false; + } + } + if ( + (BlockMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) || + (BlockMeta == E_META_BIG_FLOWER_LARGE_FERN) + ) // tall grass and fern do not work + { + return false; + } + + // spawn flower item + BroadcastSoundParticleEffect(EffectID::PARTICLE_HAPPY_VILLAGER, a_BlockX, a_BlockY, a_BlockZ, 0); + cItems FlowerItem; + FlowerItem.Add(E_BLOCK_BIG_FLOWER, 1, BlockMeta); + SpawnItemPickups(FlowerItem, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); + return true; + } + } // switch (BlockType) return false; } diff --git a/src/World.h b/src/World.h index 2181671ad..faddc6f59 100644 --- a/src/World.h +++ b/src/World.h @@ -937,6 +937,8 @@ private: bool m_IsPumpkinBonemealable; bool m_IsSaplingBonemealable; bool m_IsSugarcaneBonemealable; + bool m_IsBigFlowerBonemealable; + bool m_IsTallGrassBonemealable; /** Whether command blocks are enabled or not */ bool m_bCommandBlocksEnabled;