1
0
Fork 0

* 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.
This commit is contained in:
Samuel Barney 2015-08-19 10:45:53 -06:00
parent dffa8a7b56
commit cc83c4641d
11 changed files with 256 additions and 30 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(...)

View File

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

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

View File

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