From cc83c4641d50818bf4fd830653438515ed5264d3 Mon Sep 17 00:00:00 2001 From: Samuel Barney Date: Wed, 19 Aug 2015 10:45:53 -0600 Subject: * Logic for handling plant growth has been centralized into cBlockPlant, and all growable plants now inherit from it. * Blocks now have an effect upon plant growth, just like in vanilla. --- src/Blocks/BlockCactus.h | 25 ++++++-- src/Blocks/BlockCrops.h | 18 ++++-- src/Blocks/BlockFarmland.h | 11 ++++ src/Blocks/BlockFluid.h | 16 ++++++ src/Blocks/BlockHandler.cpp | 2 + src/Blocks/BlockHandler.h | 3 + src/Blocks/BlockNetherWart.h | 9 +-- src/Blocks/BlockNetherrack.h | 12 ++++ src/Blocks/BlockPlant.h | 132 +++++++++++++++++++++++++++++++++++++++++++ src/Blocks/BlockStems.h | 33 +++++++---- src/Blocks/BlockSugarcane.h | 25 ++++++-- 11 files changed, 256 insertions(+), 30 deletions(-) create mode 100644 src/Blocks/BlockNetherrack.h create mode 100644 src/Blocks/BlockPlant.h diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h index cb6cecc7b..29e86d085 100644 --- a/src/Blocks/BlockCactus.h +++ b/src/Blocks/BlockCactus.h @@ -1,18 +1,19 @@ #pragma once -#include "BlockHandler.h" +#include "BlockPlant.h" class cBlockCactusHandler : - public cBlockHandler + public cBlockPlant { + typedef cBlockPlant Super; public: cBlockCactusHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : Super(a_BlockType, false) { } @@ -64,7 +65,10 @@ 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 { - a_Chunk.GetWorld()->GrowCactus(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, 1); + if (CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ) == paGrowth) + { + a_Chunk.GetWorld()->GrowCactus(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, 1); + } } virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override @@ -72,6 +76,19 @@ public: UNUSED(a_Meta); return 7; } + +protected: + + virtual PlantAction CanGrow(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + { + auto Action = paStay; + if (((a_RelY + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR)) + { + Action = Super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); + } + + return Action; + } } ; diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index c54625561..9014f7046 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -1,7 +1,7 @@ #pragma once -#include "BlockHandler.h" +#include "BlockPlant.h" #include "../FastRandom.h" @@ -10,11 +10,12 @@ /** Common class that takes care of carrots, potatoes and wheat */ class cBlockCropsHandler : - public cBlockHandler + public cBlockPlant { + typedef cBlockPlant Super; public: cBlockCropsHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : Super(a_BlockType, true) { } @@ -82,12 +83,17 @@ public: { Light = SkyLight; } - - if ((Meta < 7) && (Light > 8)) + + // Check to see if the plant can grow + auto Action = CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); + + // If there is still room to grow and the plant can grow, then grow. + // Otherwise if the plant needs to die, then dig it up + if ((Meta < 7) && (Action == paGrowth)) { a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, ++Meta); } - else if (Light < 9) + else if (Action == paDeath) { a_Chunk.GetWorld()->DigBlock(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width); } diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index 886823ed6..e6c7f16f6 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -127,6 +127,17 @@ public: return false; } + + virtual bool CanSustainPlant(BLOCKTYPE a_Plant) override + { + return ( + (a_Plant == E_BLOCK_CROPS) || + (a_Plant == E_BLOCK_CARROTS) || + (a_Plant == E_BLOCK_POTATOES) || + (a_Plant == E_BLOCK_MELON_STEM) || + (a_Plant == E_BLOCK_PUMPKIN_STEM) + ); + } } ; diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index 56a2ad3c2..2d9adbab5 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -57,6 +57,17 @@ public: ASSERT(!"Unhandled blocktype in fluid/water handler!"); return 0; } + + virtual bool CanSustainPlant(BLOCKTYPE a_Plant) override + { + return ( + (a_Plant == E_BLOCK_CROPS) || + (a_Plant == E_BLOCK_CARROTS) || + (a_Plant == E_BLOCK_POTATOES) || + (a_Plant == E_BLOCK_MELON_STEM) || + (a_Plant == E_BLOCK_PUMPKIN_STEM) + ); + } } ; @@ -144,6 +155,11 @@ public: UNUSED(a_Meta); return 4; } + + virtual bool CanSustainPlant(BLOCKTYPE a_Plant) override + { + return false; + } } ; diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index ae5274d02..dab99e53d 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -49,6 +49,7 @@ #include "BlockMobSpawner.h" #include "BlockMushroom.h" #include "BlockMycelium.h" +#include "BlockNetherrack.h" #include "BlockNetherWart.h" #include "BlockOre.h" #include "BlockPiston.h" @@ -263,6 +264,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType); case E_BLOCK_NETHER_WART: return new cBlockNetherWartHandler (a_BlockType); + case E_BLOCK_NETHERRACK: return new cBlockNetherrack (a_BlockType); case E_BLOCK_NETHER_QUARTZ_ORE: return new cBlockOreHandler (a_BlockType); case E_BLOCK_NEW_LEAVES: return new cBlockLeavesHandler (a_BlockType); case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType); diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index c2a9e1769..0159230a2 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -88,6 +88,9 @@ public: /** Checks if the block can stay at the specified relative coords in the chunk */ virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk); + + /** Checks whether the block has an effect on growing the plant */ + virtual bool CanSustainPlant(BLOCKTYPE a_Plant) { return false; } /** Checks if the block can be placed at this point. Default: CanBeAt(...) diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 6a76e0828..b10150a92 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -1,7 +1,7 @@ #pragma once -#include "BlockHandler.h" +#include "BlockPlant.h" #include "../FastRandom.h" #include "../World.h" @@ -10,11 +10,12 @@ class cBlockNetherWartHandler : - public cBlockHandler + public cBlockPlant { + typedef cBlockPlant Super; public: cBlockNetherWartHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : Super(a_BlockType, false) { } @@ -36,7 +37,7 @@ 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 < 7) + if ((Meta < 7) && (CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ) == paGrowth)) { a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_NETHER_WART, ++Meta); } diff --git a/src/Blocks/BlockNetherrack.h b/src/Blocks/BlockNetherrack.h new file mode 100644 index 000000000..3ccd811f3 --- /dev/null +++ b/src/Blocks/BlockNetherrack.h @@ -0,0 +1,12 @@ +#pragma once + + +#include "BlockHandler.h" + +class cBlockNetherrack : public cBlockHandler +{ +public: + cBlockNetherrack(BLOCKTYPE a_Type) : cBlockHandler(a_Type){} + + virtual bool CanSustainPlant(BLOCKTYPE a_Plant) override { return (a_Plant == E_BLOCK_NETHER_WART); } +}; diff --git a/src/Blocks/BlockPlant.h b/src/Blocks/BlockPlant.h new file mode 100644 index 000000000..0e6aca7eb --- /dev/null +++ b/src/Blocks/BlockPlant.h @@ -0,0 +1,132 @@ + +// BlockPlant.h + +// Base class for any growing block + + + + + +#pragma once + +#include "BlockHandler.h" + +class cBlockPlant : public cBlockHandler +{ + typedef cBlockHandler Super; + bool m_NeedLightToGrow; +public: + cBlockPlant(BLOCKTYPE a_BlockType, bool a_LightToGrow) + : Super(a_BlockType), m_NeedLightToGrow(a_LightToGrow){} + +protected: + enum PlantAction + { + paDeath, + paGrowth, + paStay + }; + + /** Checks whether there is enough light for the plant to grow. + If the plant doesn't require light to grow, then it returns paGrowth. + If the plant requires light to grow and there is enough light, it returns paGrowth. + If the plant requires light to grow and there isn't enough light, it returns paStay. + If the plant requires light to grow and there is too little light, it returns paDeath. + */ + PlantAction HasEnoughLight(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) + { + // If the plant requires light to grow, check to see if there is enough light + // Otherwise, return true + if (m_NeedLightToGrow) + { + NIBBLETYPE Blocklight = a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ); + NIBBLETYPE SkyLight = a_Chunk.GetSkyLight (a_RelX, a_RelY, a_RelZ); + NIBBLETYPE Light = a_Chunk.GetTimeAlteredLight(SkyLight); + + // If the amount of light provided by blocks is greater than the sky light, use it instead + if (Blocklight > Light) + { + Light = Blocklight; + } + + // Return true if there is enough light + // Set m_ShouldDie if the base light amounts are not enough to sustain a plant + if (Light > 8) + { + return paGrowth; + } + else if (Blocklight < 9 && SkyLight < 9) + { + return paDeath; + } + + return paStay; + } + + return paGrowth; + } + + /** Checks whether a plant can grow grow, based on what is returned from cBlockPlant::HasEnoughLight + and a random check based on what is returned from cBlockPlant::GetGrowthChance. + Can return three values. + paGrowth when the conditions are right for the plant to grow. + paStay when the conditions are not quite right. + paDeath is returned when there isn't enough light for the plant to survive. + Plants that don't require light will never have a paDeath returned + */ + virtual PlantAction CanGrow(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) + { + cFastRandom rand; + // Plant can grow if it has the required amount of light, and it passes a random chance based on surrounding blocks + PlantAction Action = HasEnoughLight(a_Chunk, a_RelX, a_RelY, a_RelZ); + if ((Action == paGrowth) && (rand.NextInt(GetGrowthChance(a_Chunk, a_RelX, a_RelY, a_RelZ)) != 0)) + { + Action = paStay; + } + return Action; + } + + /** Generates a int value between 4 and 25 based on surrounding blocks that affect how quickly the plant grows. + The higher the value, the less likely the plant is to grow */ + virtual int GetGrowthChance(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) + { + float Chance = 1.0f; + a_RelY -= 1; + for (int x = -1; x < 2; ++x) + { + for (int z = -1; z < 2; ++z) + { + float Adjustment = 0.0f; + BLOCKTYPE Block; + NIBBLETYPE Meta; + + // If the chunk we are trying to get the block information from is loaded + if (a_Chunk.UnboundedRelGetBlock(a_RelX + x, a_RelY, a_RelZ + z, Block, Meta)) + { + cBlockHandler * Handler = cBlockInfo::Get(Block).m_Handler; + + // If the block affects growth, add to the adjustment + if (Handler->CanSustainPlant(m_BlockType)) + { + Adjustment = 1.0f; + + // Farmland alters the chance further if it is watered + if ((Block == E_BLOCK_FARMLAND) && (Meta != 0)) + { + Adjustment = 3.0f; + } + } + } + + // If this is not the block right underneath the plant, it has little effect on the growth + if ((x != 0) || (z != 0)) + { + Adjustment /= 4.0f; + } + + Chance += Adjustment; + } + } + return FloorC(24.0f / Chance) + 1; + } +}; diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 13b7a599f..df832c55a 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -1,7 +1,7 @@ #pragma once -#include "BlockHandler.h" +#include "BlockPlant.h" #include "../World.h" @@ -9,11 +9,12 @@ class cBlockStemsHandler : - public cBlockHandler + public cBlockPlant { + typedef cBlockPlant Super; public: cBlockStemsHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : Super(a_BlockType, true) { } @@ -25,18 +26,26 @@ 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 >= 7) + auto Action = CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); + if (Action == paGrowth) { - // 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); + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + if (Meta >= 7) + { + // 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); + } + else + { + // Grow the stem: + a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Meta + 1); + } } - else + else if (Action == paDeath) { - // Grow the stem: - a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Meta + 1); + a_Chunk.GetWorld()->DigBlock(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width); } } diff --git a/src/Blocks/BlockSugarcane.h b/src/Blocks/BlockSugarcane.h index 632dc8baa..2b4c9e583 100644 --- a/src/Blocks/BlockSugarcane.h +++ b/src/Blocks/BlockSugarcane.h @@ -1,18 +1,19 @@ #pragma once -#include "BlockHandler.h" +#include "BlockPlant.h" class cBlockSugarcaneHandler : - public cBlockHandler + public cBlockPlant { + typedef cBlockPlant Super; public: cBlockSugarcaneHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : Super(a_BlockType, false) { } @@ -73,7 +74,10 @@ 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 { - a_Chunk.GetWorld()->GrowSugarcane(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, 1); + if (CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ) == paGrowth) + { + a_Chunk.GetWorld()->GrowSugarcane(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, 1); + } } virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override @@ -81,6 +85,19 @@ public: UNUSED(a_Meta); return 7; } + +protected: + + virtual PlantAction CanGrow(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + { + auto Action = paStay; + if (((a_RelY + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR)) + { + Action = Super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ); + } + + return Action; + } } ; -- cgit v1.2.3