2013-07-29 07:13:03 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "BlockHandler.h"
|
2014-03-25 17:26:13 -04:00
|
|
|
#include "MetaRotator.h"
|
2014-09-26 13:13:19 -04:00
|
|
|
#include "Bindings/PluginManager.h"
|
2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class cBlockVineHandler :
|
|
|
|
public cBlockHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cBlockVineHandler(BLOCKTYPE a_BlockType)
|
|
|
|
: cBlockHandler(a_BlockType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual bool GetPlacementBlockTypeMeta(
|
2014-02-01 08:06:32 -05:00
|
|
|
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
|
2014-07-17 16:50:58 -04:00
|
|
|
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
2013-07-29 07:13:03 -04:00
|
|
|
int a_CursorX, int a_CursorY, int a_CursorZ,
|
|
|
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
|
|
|
) override
|
|
|
|
{
|
|
|
|
// TODO: Disallow placement where the vine doesn't attach to something properly
|
|
|
|
BLOCKTYPE BlockType = 0;
|
|
|
|
NIBBLETYPE BlockMeta;
|
2014-02-01 08:06:32 -05:00
|
|
|
a_ChunkInterface.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
2013-07-29 07:13:03 -04:00
|
|
|
if (BlockType == m_BlockType)
|
|
|
|
{
|
|
|
|
a_BlockMeta = BlockMeta | DirectionToMetaData(a_BlockFace);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
a_BlockMeta = DirectionToMetaData(a_BlockFace);
|
|
|
|
}
|
|
|
|
a_BlockType = m_BlockType;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-23 10:32:09 -04:00
|
|
|
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
|
|
|
{
|
2014-08-19 16:14:37 -04:00
|
|
|
// Reset meta to zero
|
2014-07-23 10:32:09 -04:00
|
|
|
a_Pickups.push_back(cItem(E_BLOCK_VINES, 1, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
static NIBBLETYPE DirectionToMetaData(char a_BlockFace)
|
|
|
|
{
|
|
|
|
switch (a_BlockFace)
|
|
|
|
{
|
|
|
|
case BLOCK_FACE_NORTH: return 0x1;
|
|
|
|
case BLOCK_FACE_SOUTH: return 0x4;
|
|
|
|
case BLOCK_FACE_WEST: return 0x8;
|
|
|
|
case BLOCK_FACE_EAST: return 0x2;
|
|
|
|
default: return 0x0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char MetaDataToDirection(NIBBLETYPE a_MetaData)
|
|
|
|
{
|
2014-07-21 09:19:48 -04:00
|
|
|
switch (a_MetaData)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
case 0x1: return BLOCK_FACE_NORTH;
|
|
|
|
case 0x4: return BLOCK_FACE_SOUTH;
|
|
|
|
case 0x8: return BLOCK_FACE_WEST;
|
|
|
|
case 0x2: return BLOCK_FACE_EAST;
|
|
|
|
default: return BLOCK_FACE_TOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns true if the specified block type is good for vines to attach to
|
|
|
|
static bool IsBlockAttachable(BLOCKTYPE a_BlockType)
|
|
|
|
{
|
2014-10-07 10:48:37 -04:00
|
|
|
switch (a_BlockType)
|
|
|
|
{
|
|
|
|
case E_BLOCK_GLASS:
|
|
|
|
case E_BLOCK_STAINED_GLASS:
|
|
|
|
case E_BLOCK_CHEST:
|
|
|
|
case E_BLOCK_TRAPPED_CHEST:
|
|
|
|
{
|
|
|
|
// You can't attach a vine to this solid blocks.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return cBlockInfo::IsSolid(a_BlockType);
|
|
|
|
}
|
|
|
|
}
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the meta that has the maximum allowable sides of the vine, given the surroundings
|
|
|
|
NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
|
|
|
{
|
|
|
|
static const struct
|
|
|
|
{
|
|
|
|
int x, z;
|
2014-03-30 17:13:13 -04:00
|
|
|
NIBBLETYPE Bit;
|
2013-07-29 07:13:03 -04:00
|
|
|
} Coords[] =
|
|
|
|
{
|
|
|
|
{ 0, 1, 1}, // south, ZP
|
|
|
|
{-1, 0, 2}, // west, XM
|
|
|
|
{ 0, -1, 4}, // north, ZM
|
|
|
|
{ 1, 0, 8}, // east, XP
|
|
|
|
} ;
|
2014-03-30 17:13:13 -04:00
|
|
|
NIBBLETYPE res = 0;
|
2013-12-20 10:01:34 -05:00
|
|
|
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
BLOCKTYPE BlockType;
|
|
|
|
NIBBLETYPE BlockMeta;
|
|
|
|
if (
|
|
|
|
a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) &&
|
|
|
|
IsBlockAttachable(BlockType)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
res |= Coords[i].Bit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-02 09:49:37 -05:00
|
|
|
void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
|
|
|
|
NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelX, a_RelY, a_RelZ);
|
|
|
|
|
|
|
|
// Check if vine above us, add its meta to MaxMeta
|
|
|
|
if ((a_RelY < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == m_BlockType))
|
|
|
|
{
|
|
|
|
MaxMeta |= a_Chunk.GetMeta(a_RelX, a_RelY + 1, a_RelZ);
|
|
|
|
}
|
|
|
|
|
|
|
|
NIBBLETYPE Common = CurMeta & MaxMeta; // Neighbors that we have and are legal
|
|
|
|
if (Common != CurMeta)
|
|
|
|
{
|
|
|
|
// There is a neighbor missing, need to update the meta or even destroy the block
|
|
|
|
bool HasTop = (a_RelY < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ));
|
|
|
|
if ((Common == 0) && !HasTop)
|
|
|
|
{
|
|
|
|
// The vine just lost all its support, destroy the block:
|
|
|
|
if (DoesDropOnUnsuitable())
|
|
|
|
{
|
|
|
|
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
|
|
|
|
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
|
2014-02-02 09:49:37 -05:00
|
|
|
DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, NULL, BlockX, a_RelY, BlockZ);
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Common);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Wake up the simulators for this block:
|
|
|
|
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
|
|
|
|
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
|
|
|
|
a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, &a_Chunk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual bool DoesIgnoreBuildCollision(void) override
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual bool DoesDropOnUnsuitable(void) override
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-15 13:01:55 -04:00
|
|
|
|
2014-03-07 13:42:13 -05:00
|
|
|
virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
2013-08-24 17:00:24 -04:00
|
|
|
{
|
2014-03-07 13:42:13 -05:00
|
|
|
UNUSED(a_ChunkInterface);
|
|
|
|
UNUSED(a_WorldInterface);
|
|
|
|
|
2014-10-15 13:01:55 -04:00
|
|
|
// Vine cannot grow down if at the bottom:
|
|
|
|
if (a_RelY < 1)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grow one block down, if possible:
|
2014-03-07 13:42:13 -05:00
|
|
|
BLOCKTYPE Block;
|
|
|
|
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block);
|
|
|
|
if (Block == E_BLOCK_AIR)
|
2013-08-24 17:00:24 -04:00
|
|
|
{
|
2014-10-15 13:01:55 -04:00
|
|
|
if (!a_BlockPluginInterface.CallHookBlockSpread(a_RelX + a_Chunk.GetPosX() * cChunkDef::Width, a_RelY - 1, a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width, ssVineSpread))
|
2014-03-16 11:06:03 -04:00
|
|
|
{
|
|
|
|
a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
|
|
|
|
}
|
2013-08-24 17:00:24 -04:00
|
|
|
}
|
|
|
|
}
|
2013-07-29 07:13:03 -04:00
|
|
|
|
2014-10-15 13:01:55 -04:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
|
|
|
|
{
|
|
|
|
return ((a_Meta >> 1) | (a_Meta << 3)) & 0x0f; // Rotate bits to the right
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
|
|
|
|
{
|
|
|
|
return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left
|
|
|
|
}
|
2014-03-02 07:02:29 -05:00
|
|
|
|
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
|
|
|
|
{
|
|
|
|
// Bits 2 and 4 stay, bits 1 and 3 swap
|
2014-04-01 08:55:46 -04:00
|
|
|
return (NIBBLETYPE)((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2));
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
|
|
|
|
{
|
|
|
|
// Bits 1 and 3 stay, bits 2 and 4 swap
|
2014-04-01 08:55:46 -04:00
|
|
|
return (NIBBLETYPE)((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
|
2013-07-29 07:13:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|