summaryrefslogtreecommitdiffstats
path: root/src/Blocks/BlockStems.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Blocks/BlockStems.h146
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>;