1
0

Merge pull request #2391 from SamJBarney/CropGrowthFix

Crop/plant growth fix
This commit is contained in:
Samuel Barney 2015-08-19 11:05:30 -06:00
commit b5ed23d2a6
11 changed files with 256 additions and 30 deletions

View File

@ -1,18 +1,19 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockPlant.h"
class cBlockCactusHandler : class cBlockCactusHandler :
public cBlockHandler public cBlockPlant
{ {
typedef cBlockPlant Super;
public: public:
cBlockCactusHandler(BLOCKTYPE a_BlockType) 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 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 virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
@ -72,6 +76,19 @@ public:
UNUSED(a_Meta); UNUSED(a_Meta);
return 7; 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;
}
} ; } ;

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockPlant.h"
#include "../FastRandom.h" #include "../FastRandom.h"
@ -10,11 +10,12 @@
/** Common class that takes care of carrots, potatoes and wheat */ /** Common class that takes care of carrots, potatoes and wheat */
class cBlockCropsHandler : class cBlockCropsHandler :
public cBlockHandler public cBlockPlant
{ {
typedef cBlockPlant Super;
public: public:
cBlockCropsHandler(BLOCKTYPE a_BlockType) cBlockCropsHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType) : Super(a_BlockType, true)
{ {
} }
@ -83,11 +84,16 @@ public:
Light = SkyLight; 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); 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); a_Chunk.GetWorld()->DigBlock(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width);
} }

View File

@ -127,6 +127,17 @@ public:
return false; 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)
);
}
} ; } ;

View File

@ -57,6 +57,17 @@ public:
ASSERT(!"Unhandled blocktype in fluid/water handler!"); ASSERT(!"Unhandled blocktype in fluid/water handler!");
return 0; 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); UNUSED(a_Meta);
return 4; return 4;
} }
virtual bool CanSustainPlant(BLOCKTYPE a_Plant) override
{
return false;
}
} ; } ;

View File

@ -49,6 +49,7 @@
#include "BlockMobSpawner.h" #include "BlockMobSpawner.h"
#include "BlockMushroom.h" #include "BlockMushroom.h"
#include "BlockMycelium.h" #include "BlockMycelium.h"
#include "BlockNetherrack.h"
#include "BlockNetherWart.h" #include "BlockNetherWart.h"
#include "BlockOre.h" #include "BlockOre.h"
#include "BlockPiston.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_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (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_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_NETHER_QUARTZ_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_NEW_LEAVES: return new cBlockLeavesHandler (a_BlockType); case E_BLOCK_NEW_LEAVES: return new cBlockLeavesHandler (a_BlockType);
case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType); case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType);

View File

@ -89,6 +89,9 @@ public:
/** Checks if the block can stay at the specified relative coords in the chunk */ /** 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); 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. /** Checks if the block can be placed at this point.
Default: CanBeAt(...) Default: CanBeAt(...)
NOTE: This call doesn't actually place the block NOTE: This call doesn't actually place the block

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockPlant.h"
#include "../FastRandom.h" #include "../FastRandom.h"
#include "../World.h" #include "../World.h"
@ -10,11 +10,12 @@
class cBlockNetherWartHandler : class cBlockNetherWartHandler :
public cBlockHandler public cBlockPlant
{ {
typedef cBlockPlant Super;
public: public:
cBlockNetherWartHandler(BLOCKTYPE a_BlockType) 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 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); 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); a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_NETHER_WART, ++Meta);
} }

View File

@ -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); }
};

132
src/Blocks/BlockPlant.h Normal file
View File

@ -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;
}
};

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockPlant.h"
#include "../World.h" #include "../World.h"
@ -9,11 +9,12 @@
class cBlockStemsHandler : class cBlockStemsHandler :
public cBlockHandler public cBlockPlant
{ {
typedef cBlockPlant Super;
public: public:
cBlockStemsHandler(BLOCKTYPE a_BlockType) 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 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); auto Action = CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ);
if (Meta >= 7) if (Action == paGrowth)
{ {
// Grow the produce: NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; if (Meta >= 7)
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; {
a_Chunk.GetWorld()->GrowMelonPumpkin(BlockX, a_RelY, BlockZ, m_BlockType); // 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.GetWorld()->DigBlock(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width);
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Meta + 1);
} }
} }

View File

@ -1,18 +1,19 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockPlant.h"
class cBlockSugarcaneHandler : class cBlockSugarcaneHandler :
public cBlockHandler public cBlockPlant
{ {
typedef cBlockPlant Super;
public: public:
cBlockSugarcaneHandler(BLOCKTYPE a_BlockType) 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 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 virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
@ -81,6 +85,19 @@ public:
UNUSED(a_Meta); UNUSED(a_Meta);
return 7; 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;
}
} ; } ;