diff options
Diffstat (limited to '')
-rw-r--r-- | src/Blocks/BlockStems.h | 146 |
1 files changed, 121 insertions, 25 deletions
diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 132526b93..0eb091b3c 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -7,7 +7,11 @@ -class cBlockStemsHandler : +/** Handler for stems from which produce grows in an adjacent block (melon, pumpkin) after it becomes ripe (meta == 7). +ProduceBlockType is the blocktype for the produce to be grown. +StemPickupType is the item type for the pickup resulting from breaking the stem. */ +template <BLOCKTYPE ProduceBlockType, ENUM_ITEM_ID StemPickupType> +class cBlockStemsHandler: public cBlockPlant<true> { using super = cBlockPlant<true>; @@ -25,51 +29,143 @@ public: virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override { - auto itemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; - return cItem(itemType, 1, 0); + return cItem(StemPickupType, 1, 0); } - virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + { + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_FARMLAND)); + } + + + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override + { + UNUSED(a_Meta); + return 7; + } + + + + + + virtual int Grow(cChunk & a_Chunk, Vector3i a_RelPos, int a_NumStages = 1) override { - auto Action = CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); - if (Action == paGrowth) + auto oldMeta = a_Chunk.GetMeta(a_RelPos); + auto meta = oldMeta + a_NumStages; + a_Chunk.SetBlock(a_RelPos, m_BlockType, static_cast<NIBBLETYPE>(std::min(meta, 7))); // Update the stem + if (meta > 7) { - NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); - if (Meta >= 7) + if (growProduce(a_Chunk, a_RelPos)) { - // Grow the produce: - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GrowMelonPumpkin(BlockX, a_RelY, BlockZ, m_BlockType); + return 8 - oldMeta; } else { - // Grow the stem: - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Meta + 1); + return 7 - oldMeta; } } - else if (Action == paDeath) - { - a_Chunk.GetWorld()->DigBlock(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width); - } + return meta - oldMeta; } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override - { - return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_FARMLAND)); - } - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override + + +protected: + + /** Grows the final produce next to the stem at the specified pos. + Returns true if successful, false if not. */ + bool growProduce(cChunk & a_Chunk, Vector3i a_StemRelPos) { - UNUSED(a_Meta); - return 7; + auto & random = GetRandomProvider(); + + // Check if there's another produce around the stem, if so, abort: + static const Vector3i neighborOfs[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + }; + bool isValid; + BLOCKTYPE blockType[4]; + NIBBLETYPE blockMeta; // unused + isValid = a_Chunk.UnboundedRelGetBlock(a_StemRelPos + neighborOfs[0], blockType[0], blockMeta); + isValid = isValid && a_Chunk.UnboundedRelGetBlock(a_StemRelPos + neighborOfs[1], blockType[1], blockMeta); + isValid = isValid && a_Chunk.UnboundedRelGetBlock(a_StemRelPos + neighborOfs[2], blockType[2], blockMeta); + isValid = isValid && a_Chunk.UnboundedRelGetBlock(a_StemRelPos + neighborOfs[3], blockType[3], blockMeta); + if ( + !isValid || + (blockType[0] == ProduceBlockType) || + (blockType[1] == ProduceBlockType) || + (blockType[2] == ProduceBlockType) || + (blockType[3] == ProduceBlockType) + ) + { + // Neighbors not valid or already taken by the same produce + return false; + } + + // Pick a direction in which to place the produce: + int x = 0, z = 0; + int checkType = random.RandInt(3); // The index to the neighbors array which should be checked for emptiness + switch (checkType) + { + case 0: x = 1; break; + case 1: x = -1; break; + case 2: z = 1; break; + case 3: z = -1; break; + } + + // Check that the block in that direction is empty: + switch (blockType[checkType]) + { + case E_BLOCK_AIR: + case E_BLOCK_SNOW: + case E_BLOCK_TALL_GRASS: + case E_BLOCK_DEAD_BUSH: + { + break; + } + default: return false; + } + + // Check if there's soil under the neighbor. We already know the neighbors are valid. Place produce if ok + BLOCKTYPE soilType; + auto produceRelPos = a_StemRelPos + Vector3i(x, 0, z); + VERIFY(a_Chunk.UnboundedRelGetBlock(produceRelPos.addedY(-1), soilType, blockMeta)); + switch (soilType) + { + case E_BLOCK_DIRT: + case E_BLOCK_GRASS: + case E_BLOCK_FARMLAND: + { + // Place a randomly-facing produce: + NIBBLETYPE meta = (ProduceBlockType == E_BLOCK_MELON) ? 0 : static_cast<NIBBLETYPE>(random.RandInt(4) % 4); + auto produceAbsPos = a_Chunk.RelativeToAbsolute(produceRelPos); + FLOGD("Growing melon / pumpkin at {0} (<{1}, {2}> from stem), overwriting {3}, growing on top of {4}, meta {5}", + produceAbsPos, + x, z, + ItemTypeToString(blockType[checkType]), + ItemTypeToString(soilType), + meta + ); + a_Chunk.GetWorld()->SetBlock(produceAbsPos, ProduceBlockType, meta); + return true; + } + } + return false; } } ; +using cBlockMelonStemHandler = cBlockStemsHandler<E_BLOCK_MELON, E_ITEM_MELON_SEEDS>; +using cBlockPumpkinStemHandler = cBlockStemsHandler<E_BLOCK_PUMPKIN, E_ITEM_PUMPKIN_SEEDS>; |