summaryrefslogtreecommitdiffstats
path: root/src/Blocks
diff options
context:
space:
mode:
Diffstat (limited to 'src/Blocks')
-rw-r--r--src/Blocks/BlockSapling.h142
1 files changed, 135 insertions, 7 deletions
diff --git a/src/Blocks/BlockSapling.h b/src/Blocks/BlockSapling.h
index bec79c6f3..c15e0a195 100644
--- a/src/Blocks/BlockSapling.h
+++ b/src/Blocks/BlockSapling.h
@@ -3,6 +3,7 @@
#include "BlockHandler.h"
#include "../World.h"
+#include "../FastRandom.h"
@@ -34,17 +35,144 @@ public:
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
-
- if ((Meta & 0x08) != 0)
+ NIBBLETYPE Light = std::max(a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(a_RelX, a_RelY, a_RelZ)));
+
+ // Only grow if we have the right amount of light
+ if (Light > 8)
+ {
+ cFastRandom random;
+ // Only grow if we are in the right growth stage and have the right amount of space around them.
+ if (((Meta & 0x08) != 0) && (random.NextInt(99) < 45) && CanGrowAt(a_Chunk, a_RelX, a_RelY, a_RelZ, Meta))
+ {
+ int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
+ int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
+ a_Chunk.GetWorld()->GrowTree(BlockX, a_RelY, BlockZ);
+ }
+ // Only move to the next growth stage if we haven't gone there yet
+ else if (((Meta & 0x08) == 0) && (random.NextInt(99) < 45))
+ {
+ a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta | 0x08);
+ }
+ }
+ }
+
+ bool CanGrowAt(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
+ {
+ a_Meta = a_Meta & 0x07;
+ int CheckHeight = 0;
+ bool LargeTree = false;
+
+ // Get the height to check against
+ switch (a_Meta)
{
- int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
- int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
- a_Chunk.GetWorld()->GrowTree(BlockX, a_RelY, BlockZ);
+ case E_META_SAPLING_APPLE:
+ {
+ CheckHeight = 5;
+ break;
+ }
+ case E_META_SAPLING_CONIFER:
+ {
+ CheckHeight = 7;
+ if (IsLargeTree(a_Chunk, a_RelX, a_RelY, a_RelZ, a_Meta))
+ {
+ CheckHeight = 16;
+ LargeTree = true;
+ }
+ break;
+ }
+ case E_META_SAPLING_BIRCH:
+ {
+ CheckHeight = 6;
+ break;
+ }
+ case E_META_SAPLING_JUNGLE:
+ {
+ CheckHeight = 7;
+ if (IsLargeTree(a_Chunk, a_RelX, a_RelY, a_RelZ, a_Meta))
+ {
+ CheckHeight = 13;
+ LargeTree = true;
+ }
+ break;
+ }
+ // Dark Oaks only grow in a 2x2 area
+ case E_META_SAPLING_DARK_OAK:
+ {
+ if (!IsLargeTree(a_Chunk, a_RelX, a_RelY, a_RelZ, a_Meta))
+ {
+ return false;
+ }
+ CheckHeight = 7;
+ LargeTree = true;
+ break;
+ }
}
- else
+ // We should always get a valid CheckHeight
+ ASSERT(CheckHeight != 0);
+
+ // Don't grow a tree if we don't have enough space left above it in the chunk
+ if ((a_RelY + CheckHeight) > cChunkDef::Height)
+ {
+ return false;
+ }
+ bool CanGrow = true;
+
+ // Validate the neighbor blocks. They cannot be solid.
+ BLOCKTYPE check = E_BLOCK_AIR;
+ a_Chunk.UnboundedRelGetBlockType(a_RelX - 1, a_RelY, a_RelZ, check);
+ CanGrow = CanGrow && cBlockInfo::IsTransparent(check);
+
+ a_Chunk.UnboundedRelGetBlockType(a_RelX + 1, a_RelY, a_RelZ, check);
+ CanGrow = CanGrow && cBlockInfo::IsTransparent(check);
+
+ a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ - 1, check);
+ CanGrow = CanGrow && cBlockInfo::IsTransparent(check);
+
+ a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ + 1, check);
+ CanGrow = CanGrow && cBlockInfo::IsTransparent(check);
+
+
+
+ while (CheckHeight && CanGrow)
{
- a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta | 0x08);
+ check = a_Chunk.GetBlock(a_RelX, a_RelY + CheckHeight, a_RelZ);
+ CanGrow = CanGrow && ((check == E_BLOCK_AIR) || (check == E_BLOCK_LEAVES));
+
+ // We have to check above the neighboring saplings as well
+ if (LargeTree)
+ {
+ a_Chunk.UnboundedRelGetBlockType(a_RelX + 1, a_RelY + CheckHeight, a_RelZ, check);
+ CanGrow = CanGrow && ((check == E_BLOCK_AIR) || (check == E_BLOCK_LEAVES));
+
+ a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY + CheckHeight, a_RelZ + 1, check);
+ CanGrow = CanGrow && ((check == E_BLOCK_AIR) || (check == E_BLOCK_LEAVES));
+
+ a_Chunk.UnboundedRelGetBlockType(a_RelX + 1, a_RelY + CheckHeight, a_RelZ + 1, check);
+ CanGrow = CanGrow && ((check == E_BLOCK_AIR) || (check == E_BLOCK_LEAVES));
+ }
+
+ --CheckHeight;
}
+
+ return CanGrow;
+ }
+
+private:
+ bool IsLargeTree(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta)
+ {
+ BLOCKTYPE type;
+ NIBBLETYPE meta;
+ bool LargeTree = true;
+ a_Chunk.UnboundedRelGetBlock(a_RelX + 1, a_RelY, a_RelZ, type, meta);
+ LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
+
+ a_Chunk.UnboundedRelGetBlock(a_RelX + 1, a_RelY, a_RelZ + 1, type, meta);
+ LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
+
+ a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ + 1, type, meta);
+ LargeTree = LargeTree && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
+
+ return LargeTree;
}
} ;