2013-07-29 07:13:03 -04:00
# pragma once
# include "BlockHandler.h"
2014-02-01 09:01:13 -05:00
# include "../Chunk.h"
2014-10-25 16:54:00 -04:00
# include "ChunkInterface.h"
2019-10-16 04:06:34 -04:00
# include "Mixins.h"
2013-07-29 07:13:03 -04:00
2020-10-05 06:27:14 -04:00
class cBlockTorchBaseHandler :
public cMetaRotator < cBlockHandler , 0x7 , 0x4 , 0x1 , 0x3 , 0x2 >
2013-07-29 07:13:03 -04:00
{
2020-10-05 06:27:14 -04:00
using Super = cMetaRotator < cBlockHandler , 0x7 , 0x4 , 0x1 , 0x3 , 0x2 > ;
2019-10-16 04:06:34 -04:00
2013-07-29 07:13:03 -04:00
public :
2019-10-16 04:06:34 -04:00
2020-09-20 09:50:52 -04:00
using Super : : Super ;
2020-04-21 16:19:22 -04:00
2020-10-05 06:27:14 -04:00
protected :
~ cBlockTorchBaseHandler ( ) = default ;
2020-09-20 09:50:52 -04:00
private :
2020-04-21 16:19:22 -04:00
2013-07-29 07:13:03 -04:00
virtual bool GetPlacementBlockTypeMeta (
2020-04-21 16:19:22 -04:00
cChunkInterface & a_ChunkInterface ,
cPlayer & a_Player ,
const Vector3i a_PlacedBlockPos ,
eBlockFace a_ClickedBlockFace ,
const Vector3i a_CursorPos ,
2013-07-29 07:13:03 -04:00
BLOCKTYPE & a_BlockType , NIBBLETYPE & a_BlockMeta
2020-09-20 09:50:52 -04:00
) const override
2013-07-29 07:13:03 -04:00
{
2020-04-21 16:19:22 -04:00
BLOCKTYPE ClickedBlockType ;
NIBBLETYPE ClickedBlockMeta ;
auto ClickedBlockPos = AddFaceDirection ( a_PlacedBlockPos , a_ClickedBlockFace , true ) ;
a_ChunkInterface . GetBlockTypeMeta ( ClickedBlockPos , ClickedBlockType , ClickedBlockMeta ) ;
if ( ! CanBePlacedOn ( ClickedBlockType , ClickedBlockMeta , a_ClickedBlockFace ) )
2013-07-29 07:13:03 -04:00
{
2020-04-21 16:19:22 -04:00
// Couldn't be placed on whatever face was clicked, last ditch resort - find another face
a_ClickedBlockFace = FindSuitableFace ( a_ChunkInterface , a_PlacedBlockPos ) ; // Set a_BlockFace to a valid direction which will be converted later to a metadata
if ( a_ClickedBlockFace = = BLOCK_FACE_NONE )
2013-07-29 07:13:03 -04:00
{
2014-10-03 16:38:23 -04:00
// No attachable face found - don't place the torch
2013-07-29 07:13:03 -04:00
return false ;
}
}
a_BlockType = m_BlockType ;
2020-04-21 16:19:22 -04:00
a_BlockMeta = BlockFaceToMetaData ( a_ClickedBlockFace ) ;
2013-07-29 07:13:03 -04:00
return true ;
}
2020-04-21 16:19:22 -04:00
/** Converts the block face of the neighbor to which the torch is attached, to the torch block's meta. */
inline static NIBBLETYPE BlockFaceToMetaData ( eBlockFace a_NeighborBlockFace )
2013-12-06 14:23:27 -05:00
{
2020-04-21 16:19:22 -04:00
switch ( a_NeighborBlockFace )
2013-07-29 07:13:03 -04:00
{
case BLOCK_FACE_BOTTOM : ASSERT ( ! " Shouldn't be getting this face " ) ; return 0 ;
case BLOCK_FACE_TOP : return E_META_TORCH_FLOOR ;
case BLOCK_FACE_EAST : return E_META_TORCH_EAST ;
case BLOCK_FACE_WEST : return E_META_TORCH_WEST ;
case BLOCK_FACE_NORTH : return E_META_TORCH_NORTH ;
case BLOCK_FACE_SOUTH : return E_META_TORCH_SOUTH ;
2015-05-19 07:28:31 -04:00
case BLOCK_FACE_NONE :
2013-07-29 07:13:03 -04:00
{
ASSERT ( ! " Unhandled torch direction! " ) ;
break ;
}
2019-08-11 05:39:43 -04:00
}
2013-07-29 07:13:03 -04:00
return 0x0 ;
2013-12-06 14:23:27 -05:00
}
2013-07-29 07:13:03 -04:00
2020-04-21 16:19:22 -04:00
/** Converts the torch block's meta to the block face of the neighbor to which the torch is attached. */
inline static eBlockFace MetaDataToBlockFace ( NIBBLETYPE a_MetaData )
2013-12-06 14:24:45 -05:00
{
2013-07-29 07:13:03 -04:00
switch ( a_MetaData )
{
2013-12-06 14:24:45 -05:00
case 0 : return BLOCK_FACE_TOP ; // By default, the torches stand on the ground
2013-07-29 07:13:03 -04:00
case E_META_TORCH_FLOOR : return BLOCK_FACE_TOP ;
case E_META_TORCH_EAST : return BLOCK_FACE_EAST ;
case E_META_TORCH_WEST : return BLOCK_FACE_WEST ;
case E_META_TORCH_NORTH : return BLOCK_FACE_NORTH ;
case E_META_TORCH_SOUTH : return BLOCK_FACE_SOUTH ;
default :
{
ASSERT ( ! " Unhandled torch metadata " ) ;
break ;
}
}
2014-02-04 13:59:05 -05:00
return BLOCK_FACE_TOP ;
2013-12-06 14:24:45 -05:00
}
2013-07-29 07:13:03 -04:00
2020-04-21 16:19:22 -04:00
/** Returns true if the torch can be placed on the specified block's face. */
2014-09-30 17:00:33 -04:00
static bool CanBePlacedOn ( BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , eBlockFace a_BlockFace )
2013-07-29 07:13:03 -04:00
{
2014-09-30 17:00:33 -04:00
switch ( a_BlockType )
2013-09-15 10:55:35 -04:00
{
2014-09-30 17:00:33 -04:00
case E_BLOCK_END_PORTAL_FRAME :
case E_BLOCK_SOULSAND :
{
// Exceptional vanilla behaviour
return true ;
}
case E_BLOCK_GLASS :
case E_BLOCK_STAINED_GLASS :
case E_BLOCK_FENCE :
case E_BLOCK_NETHER_BRICK_FENCE :
2015-05-20 17:18:21 -04:00
case E_BLOCK_SPRUCE_FENCE :
case E_BLOCK_BIRCH_FENCE :
case E_BLOCK_JUNGLE_FENCE :
case E_BLOCK_DARK_OAK_FENCE :
case E_BLOCK_ACACIA_FENCE :
2014-09-30 17:00:33 -04:00
case E_BLOCK_COBBLESTONE_WALL :
{
// Torches can only be placed on top of these blocks
return ( a_BlockFace = = BLOCK_FACE_YP ) ;
}
case E_BLOCK_STONE_SLAB :
case E_BLOCK_WOODEN_SLAB :
{
2020-04-21 16:19:22 -04:00
// Toches can be placed only on the top of top-half-slabs
2014-09-30 17:00:33 -04:00
return ( ( a_BlockFace = = BLOCK_FACE_YP ) & & ( ( a_BlockMeta & 0x08 ) = = 0x08 ) ) ;
}
2015-06-30 10:50:15 -04:00
case E_BLOCK_OAK_WOOD_STAIRS :
2015-07-13 19:08:07 -04:00
case E_BLOCK_COBBLESTONE_STAIRS :
case E_BLOCK_BRICK_STAIRS :
case E_BLOCK_STONE_BRICK_STAIRS :
case E_BLOCK_NETHER_BRICK_STAIRS :
case E_BLOCK_SANDSTONE_STAIRS :
case E_BLOCK_SPRUCE_WOOD_STAIRS :
case E_BLOCK_BIRCH_WOOD_STAIRS :
case E_BLOCK_JUNGLE_WOOD_STAIRS :
case E_BLOCK_QUARTZ_STAIRS :
case E_BLOCK_ACACIA_WOOD_STAIRS :
case E_BLOCK_DARK_OAK_WOOD_STAIRS :
case E_BLOCK_RED_SANDSTONE_STAIRS :
{
return ( a_BlockFace = = BLOCK_FACE_TOP ) & & ( a_BlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN ) ;
}
2014-09-30 17:00:33 -04:00
default :
{
if ( cBlockInfo : : FullyOccupiesVoxel ( a_BlockType ) )
{
2014-10-03 16:38:23 -04:00
// Torches can be placed on all sides of full blocks except the bottom
2014-09-30 17:00:33 -04:00
return ( a_BlockFace ! = BLOCK_FACE_YM ) ;
}
return false ;
}
2013-07-29 07:13:03 -04:00
}
}
2016-02-05 16:45:45 -05:00
2020-04-21 16:19:22 -04:00
/** Returns a suitable neighbor's blockface to place the torch at the specified pos
Returns BLOCK_FACE_NONE on failure */
static eBlockFace FindSuitableFace ( cChunkInterface & a_ChunkInterface , const Vector3i a_TorchPos )
2013-07-29 07:13:03 -04:00
{
2020-04-21 16:19:22 -04:00
for ( int i = BLOCK_FACE_YM ; i < = BLOCK_FACE_XP ; i + + ) // Loop through all faces
2013-07-29 07:13:03 -04:00
{
2020-04-21 16:19:22 -04:00
auto Face = static_cast < eBlockFace > ( i ) ;
auto NeighborPos = AddFaceDirection ( a_TorchPos , Face , true ) ;
BLOCKTYPE NeighborBlockType ;
NIBBLETYPE NeighborBlockMeta ;
a_ChunkInterface . GetBlockTypeMeta ( NeighborPos , NeighborBlockType , NeighborBlockMeta ) ;
if ( CanBePlacedOn ( NeighborBlockType , NeighborBlockMeta , Face ) )
2013-07-29 07:13:03 -04:00
{
2014-02-04 14:26:39 -05:00
return Face ;
2013-07-29 07:13:03 -04:00
}
}
2013-09-15 10:55:35 -04:00
return BLOCK_FACE_NONE ;
2013-07-29 07:13:03 -04:00
}
2014-09-30 17:00:33 -04:00
2020-04-21 16:19:22 -04:00
2020-09-20 09:50:52 -04:00
virtual bool CanBeAt ( cChunkInterface & a_ChunkInterface , const Vector3i a_RelPos , const cChunk & a_Chunk ) const override
2020-04-21 16:19:22 -04:00
{
auto Face = MetaDataToBlockFace ( a_Chunk . GetMeta ( a_RelPos ) ) ;
auto NeighborRelPos = AddFaceDirection ( a_RelPos , Face , true ) ;
BLOCKTYPE NeighborBlockType ;
NIBBLETYPE NeighborBlockMeta ;
if ( ! a_Chunk . UnboundedRelGetBlock ( NeighborRelPos , NeighborBlockType , NeighborBlockMeta ) )
2013-09-15 10:55:35 -04:00
{
2020-04-21 16:19:22 -04:00
// Neighbor in an unloaded chunk, bail out without changint this.
2013-09-15 10:55:35 -04:00
return false ;
}
2014-09-30 17:00:33 -04:00
2020-04-21 16:19:22 -04:00
return CanBePlacedOn ( NeighborBlockType , NeighborBlockMeta , Face ) ;
2013-07-29 07:13:03 -04:00
}
2020-04-21 16:19:22 -04:00
2020-09-20 09:50:52 -04:00
virtual ColourID GetMapBaseColourID ( NIBBLETYPE a_Meta ) const override
2015-06-30 10:50:15 -04:00
{
UNUSED ( a_Meta ) ;
return 0 ;
}
2013-07-29 07:13:03 -04:00
} ;
2020-10-05 06:27:14 -04:00
class cBlockTorchHandler final :
public cClearMetaOnDrop < cBlockTorchBaseHandler >
{
using Super = cClearMetaOnDrop < cBlockTorchBaseHandler > ;
public :
using Super : : Super ;
} ;
class cBlockRedstoneTorchHandler final :
public cBlockTorchBaseHandler
{
using Super = cBlockTorchBaseHandler ;
public :
using Super : : Super ;
private :
2021-03-28 09:41:34 -04:00
virtual cItems ConvertToPickups ( const NIBBLETYPE a_BlockMeta , const cItem * const a_Tool ) const override
2020-10-05 06:27:14 -04:00
{
// Always drop the ON torch, meta 0:
return { E_BLOCK_REDSTONE_TORCH_ON } ;
}
virtual ColourID GetMapBaseColourID ( NIBBLETYPE a_Meta ) const override
{
UNUSED ( a_Meta ) ;
return 0 ;
}
} ;