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-03-25 17:26:13 -04:00
# include "MetaRotator.h"
2013-07-29 07:13:03 -04:00
class cBlockTorchHandler :
2014-03-25 17:26:13 -04:00
public cMetaRotator < cBlockHandler , 0x7 , 0x4 , 0x1 , 0x3 , 0x2 >
2013-07-29 07:13:03 -04:00
{
public :
cBlockTorchHandler ( BLOCKTYPE a_BlockType )
2014-03-25 17:26:13 -04:00
: cMetaRotator < cBlockHandler , 0x7 , 0x4 , 0x1 , 0x3 , 0x2 > ( a_BlockType )
2013-07-29 07:13:03 -04:00
{
}
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
{
2014-09-30 17:00:33 -04:00
BLOCKTYPE Block ;
NIBBLETYPE Meta ;
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , a_BlockFace , true ) ; // Set to clicked block
a_ChunkInterface . GetBlockTypeMeta ( a_BlockX , a_BlockY , a_BlockZ , Block , Meta ) ;
2013-09-15 10:55:35 -04:00
2014-09-30 17:00:33 -04:00
if ( ! CanBePlacedOn ( Block , Meta , a_BlockFace ) ) // Try to preserve original direction
2013-07-29 07:13:03 -04:00
{
2014-09-30 17:00:33 -04:00
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , a_BlockFace , false ) ; // Reset to torch block
a_BlockFace = FindSuitableFace ( a_ChunkInterface , a_BlockX , a_BlockY , a_BlockZ ) ; // Set a_BlockFace to a valid direction which will be converted later to a metadata
2013-09-15 10:55:35 -04:00
if ( a_BlockFace = = 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 ;
}
}
2013-09-15 10:55:35 -04:00
2013-07-29 07:13:03 -04:00
a_BlockType = m_BlockType ;
a_BlockMeta = DirectionToMetaData ( a_BlockFace ) ;
return true ;
}
2014-02-04 13:59:05 -05:00
inline static NIBBLETYPE DirectionToMetaData ( eBlockFace a_Direction )
2013-12-06 14:23:27 -05:00
{
2013-07-29 07:13:03 -04:00
switch ( a_Direction )
{
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 ;
default :
{
ASSERT ( ! " Unhandled torch direction! " ) ;
break ;
}
} ;
return 0x0 ;
2013-12-06 14:23:27 -05:00
}
2013-07-29 07:13:03 -04:00
2014-02-04 13:59:05 -05:00
inline static eBlockFace MetaDataToDirection ( 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
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 :
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 :
{
// Toches can be placed on the top of these slabs only if the occupy the top half of the voxel
return ( ( a_BlockFace = = BLOCK_FACE_YP ) & & ( ( a_BlockMeta & 0x08 ) = = 0x08 ) ) ;
}
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
}
}
2014-10-03 16:38:23 -04:00
/** Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure */
2014-02-04 13:59:05 -05:00
static eBlockFace FindSuitableFace ( cChunkInterface & a_ChunkInterface , int a_BlockX , int a_BlockY , int a_BlockZ )
2013-07-29 07:13:03 -04:00
{
2014-07-17 16:15:34 -04:00
for ( int i = BLOCK_FACE_YM ; i < = BLOCK_FACE_XP ; i + + ) // Loop through all directions
2013-07-29 07:13:03 -04:00
{
2014-02-04 14:26:39 -05:00
eBlockFace Face = static_cast < eBlockFace > ( i ) ;
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , Face , true ) ;
2014-09-30 17:00:33 -04:00
BLOCKTYPE BlockInQuestion ;
NIBBLETYPE BlockInQuestionMeta ;
a_ChunkInterface . GetBlockTypeMeta ( a_BlockX , a_BlockY , a_BlockZ , BlockInQuestion , BlockInQuestionMeta ) ;
if ( CanBePlacedOn ( BlockInQuestion , BlockInQuestionMeta , 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
else
{
2013-12-06 14:35:10 -05:00
// Reset coords in preparation for next iteration
2014-02-04 14:26:39 -05:00
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , Face , false ) ;
2013-09-15 10:55:35 -04:00
}
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-02-01 08:06:32 -05:00
virtual bool CanBeAt ( cChunkInterface & a_ChunkInterface , int a_RelX , int a_RelY , int a_RelZ , const cChunk & a_Chunk ) override
2013-07-29 07:13:03 -04:00
{
2014-02-04 13:59:05 -05:00
eBlockFace Face = MetaDataToDirection ( a_Chunk . GetMeta ( a_RelX , a_RelY , a_RelZ ) ) ;
2013-09-15 10:55:35 -04:00
AddFaceDirection ( a_RelX , a_RelY , a_RelZ , Face , true ) ;
2014-09-30 17:00:33 -04:00
2013-09-15 10:55:35 -04:00
BLOCKTYPE BlockInQuestion ;
2014-09-30 17:00:33 -04:00
NIBBLETYPE BlockInQuestionMeta ;
if ( ! a_Chunk . UnboundedRelGetBlock ( a_RelX , a_RelY , a_RelZ , BlockInQuestion , BlockInQuestionMeta ) )
2013-09-15 10:55:35 -04:00
{
return false ;
}
2014-09-30 17:00:33 -04:00
return CanBePlacedOn ( BlockInQuestion , BlockInQuestionMeta , Face ) ;
2013-07-29 07:13:03 -04:00
}
virtual void ConvertToPickups ( cItems & a_Pickups , NIBBLETYPE a_BlockMeta ) override
{
// Always drop meta = 0
a_Pickups . push_back ( cItem ( m_BlockType , 1 , 0 ) ) ;
}
} ;