diff options
Diffstat (limited to 'src/Blocks/BlockVines.h')
-rw-r--r-- | src/Blocks/BlockVines.h | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/src/Blocks/BlockVines.h b/src/Blocks/BlockVines.h new file mode 100644 index 000000000..d6eccd552 --- /dev/null +++ b/src/Blocks/BlockVines.h @@ -0,0 +1,271 @@ +#pragma once + +#include "BlockHandler.h" + + + + + +class cBlockVinesHandler final : + public cBlockHandler +{ + using Super = cBlockHandler; + +public: + + using Super::Super; + +private: + + static const NIBBLETYPE VINE_LOST_SUPPORT = 16; + static const NIBBLETYPE VINE_UNCHANGED = 17; + + + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override + { + return GetMaxMeta(a_Chunk, a_Position, a_Meta) != VINE_LOST_SUPPORT; + } + + + virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override + { + // Only drops self when using shears, otherwise drops nothing: + if ((a_Tool == nullptr) || (a_Tool->m_ItemType != E_ITEM_SHEARS)) + { + return {}; + } + return cItem(E_BLOCK_VINES, 1, 0); + } + + + + + + static char MetaDataToDirection(NIBBLETYPE a_MetaData) + { + switch (a_MetaData) + { + 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) + { + switch (a_BlockType) + { + case E_BLOCK_CHEST: + case E_BLOCK_ENDER_CHEST: + case E_BLOCK_GLASS: + case E_BLOCK_PISTON: + case E_BLOCK_PISTON_EXTENSION: + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_STAINED_GLASS: + case E_BLOCK_STICKY_PISTON: + case E_BLOCK_TRAPPED_CHEST: + { + // You can't attach a vine to this solid blocks. + return false; + } + default: + { + return cBlockInfo::IsSolid(a_BlockType); + } + } + } + + + + + + /** Returns the meta that has the maximum allowable sides of the vine, given the surroundings and current vine meta. + Returns special values for a vine that can continue to exist unchanged, or must die completely. */ + static NIBBLETYPE GetMaxMeta(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_CurrentMeta) + { + static const struct + { + int x, z; + NIBBLETYPE Bit; + } Coords[] = + { + { 0, 1, 1}, // south, ZP + {-1, 0, 2}, // west, XM + { 0, -1, 4}, // north, ZM + { 1, 0, 8}, // east, XP + } ; + + NIBBLETYPE MaxMeta = 0; + for (auto & Coord : Coords) + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + auto checkPos = a_Position.addedXZ(Coord.x, Coord.z); + if ( + a_Chunk.UnboundedRelGetBlock(checkPos.x, checkPos.y, checkPos.z, BlockType, BlockMeta) && + IsBlockAttachable(BlockType) + ) + { + MaxMeta |= Coord.Bit; + } + } + + // Check if vine above us, add its meta to MaxMeta: + if ((a_Position.y < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_Position.addedY(1)) == E_BLOCK_VINES)) + { + MaxMeta |= a_Chunk.GetMeta(a_Position.addedY(1)); + } + + NIBBLETYPE Common = a_CurrentMeta & MaxMeta; // Neighbors that we have and are legal. + if (Common != a_CurrentMeta) + { + bool HasTop = (a_Position.y < (cChunkDef::Height - 1)) && IsBlockAttachable(a_Chunk.GetBlock(a_Position.addedY(1))); + if ((Common == 0) && !HasTop) // Meta equals 0 also means top. Make a last-ditch attempt to save the vine. + { + return VINE_LOST_SUPPORT; + } + + return Common; + } + + return VINE_UNCHANGED; + } + + + + + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const override + { + a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) + { + + const auto Position = cChunkDef::AbsoluteToRelative(a_BlockPos); + const auto MaxMeta = GetMaxMeta(a_Chunk, Position, a_Chunk.GetMeta(Position)); + + if (MaxMeta == VINE_UNCHANGED) + { + return false; + } + + // There is a neighbor missing, need to update the meta or even destroy the block. + + if (MaxMeta == VINE_LOST_SUPPORT) + { + // The vine just lost all its support, destroy the block: + a_Chunk.SetBlock(Position, E_BLOCK_AIR, 0); + } + else + { + // It lost some of its support, set it to what remains (SetBlock to notify neighbors): + a_Chunk.SetBlock(Position, E_BLOCK_VINES, MaxMeta); + } + + return false; + }); + } + + + + + + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override + { + return !a_ClickedDirectly || (a_HeldItem.m_ItemType != m_BlockType); + } + + + + + + virtual void OnUpdate( + cChunkInterface & a_ChunkInterface, + cWorldInterface & a_WorldInterface, + cBlockPluginInterface & a_PluginInterface, + cChunk & a_Chunk, + const Vector3i a_RelPos + ) const override + { + UNUSED(a_ChunkInterface); + UNUSED(a_WorldInterface); + + // Vine cannot grow down if at the bottom: + auto GrowPos = a_RelPos.addedY(-1); + if (!cChunkDef::IsValidHeight(GrowPos.y)) + { + return; + } + + // Grow one block down, if possible: + BLOCKTYPE Block; + a_Chunk.UnboundedRelGetBlockType(GrowPos, Block); + if (Block == E_BLOCK_AIR) + { + auto WorldPos = a_Chunk.RelativeToAbsolute(GrowPos); + if (!a_PluginInterface.CallHookBlockSpread(WorldPos.x, WorldPos.y, WorldPos.z, ssVineSpread)) + { + a_Chunk.UnboundedRelSetBlock(GrowPos, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelPos)); + } + } + } + + + + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) const override + { + return ((a_Meta >> 1) | (a_Meta << 3)) & 0x0f; // Rotate bits to the right + } + + + + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) const override + { + return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left + } + + + + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) const override + { + // Bits 2 and 4 stay, bits 1 and 3 swap + return static_cast<NIBBLETYPE>((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2)); + } + + + + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) const override + { + // Bits 1 and 3 stay, bits 2 and 4 swap + return static_cast<NIBBLETYPE>((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); + } + + + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override + { + UNUSED(a_Meta); + return 7; + } +} ; + + + + |