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-02-04 13:59:05 -05: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
{
2013-09-15 10:55:35 -04:00
// Find proper placement of torch
if ( ( a_BlockFace = = BLOCK_FACE_TOP ) | | ( a_BlockFace = = BLOCK_FACE_BOTTOM ) )
2013-07-29 07:13:03 -04:00
{
2014-01-31 18:17:41 -05:00
a_BlockFace = FindSuitableFace ( a_ChunkInterface , a_BlockX , a_BlockY , a_BlockZ ) ; // Top or bottom faces clicked, find a suitable face
2013-09-15 10:55:35 -04:00
if ( a_BlockFace = = BLOCK_FACE_NONE )
2013-07-29 07:13:03 -04:00
{
2013-09-15 10:55:35 -04:00
// Client wouldn't have sent anything anyway, but whatever
2013-07-29 07:13:03 -04:00
return false ;
}
}
2013-09-15 10:55:35 -04:00
else
{
// Not top or bottom faces, try to preserve whatever face was clicked
2014-02-02 07:43:57 -05:00
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , a_BlockFace , true ) ; // Set to clicked block
2014-02-01 08:06:32 -05:00
if ( ! CanBePlacedOn ( a_ChunkInterface . GetBlock ( a_BlockX , a_BlockY , a_BlockZ ) , a_BlockFace ) )
2013-09-15 10:55:35 -04:00
{
2014-02-02 07:43:57 -05:00
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , a_BlockFace , false ) ; // Reset to torch block
2013-09-15 10:55:35 -04:00
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
2014-01-31 18:17:41 -05:00
a_BlockFace = FindSuitableFace ( a_ChunkInterface , a_BlockX , a_BlockY , a_BlockZ ) ;
2013-09-15 10:55:35 -04:00
if ( a_BlockFace = = BLOCK_FACE_NONE )
{
return false ;
}
}
}
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-02-04 13:59:05 -05:00
static bool CanBePlacedOn ( BLOCKTYPE a_BlockType , eBlockFace a_BlockFace )
2013-07-29 07:13:03 -04:00
{
2014-03-01 14:34:19 -05:00
if ( ! cBlockInfo : : FullyOccupiesVoxel ( a_BlockType ) )
2013-09-15 10:55:35 -04:00
{
2013-12-06 14:35:10 -05:00
return ( a_BlockFace = = BLOCK_FACE_TOP ) ; // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle
2013-08-11 10:21:31 -04:00
}
2013-09-15 10:55:35 -04:00
else
{
return true ;
2013-07-29 07:13:03 -04:00
}
}
2013-09-15 10:55:35 -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-02-04 14:26:39 -05: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-02-01 08:06:32 -05:00
BLOCKTYPE BlockInQuestion = a_ChunkInterface . GetBlock ( a_BlockX , a_BlockY , a_BlockZ ) ;
2013-09-15 10:55:35 -04:00
2013-12-06 14:35:10 -05:00
if ( // If on a block that can only hold a torch if torch is standing on it, return that face
2013-09-15 10:55:35 -04:00
( ( BlockInQuestion = = E_BLOCK_GLASS ) | |
( BlockInQuestion = = E_BLOCK_FENCE ) | |
( BlockInQuestion = = E_BLOCK_NETHER_BRICK_FENCE ) | |
( BlockInQuestion = = E_BLOCK_COBBLESTONE_WALL ) ) & &
2014-02-04 14:26:39 -05:00
( Face = = BLOCK_FACE_TOP )
2013-09-15 10:55:35 -04:00
)
{
2014-02-04 14:26:39 -05:00
return Face ;
2013-09-15 10:55:35 -04:00
}
2014-03-01 14:34:19 -05:00
else if ( cBlockInfo : : FullyOccupiesVoxel ( BlockInQuestion ) & & ( i ! = BLOCK_FACE_BOTTOM ) )
2013-07-29 07:13:03 -04:00
{
2013-12-06 14:35:10 -05:00
// Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face
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 ) ;
BLOCKTYPE BlockInQuestion ;
a_Chunk . UnboundedRelGetBlockType ( a_RelX , a_RelY , a_RelZ , BlockInQuestion ) ;
2013-09-16 14:18:36 -04:00
if (
( BlockInQuestion = = E_BLOCK_GLASS ) | |
( BlockInQuestion = = E_BLOCK_FENCE ) | |
( BlockInQuestion = = E_BLOCK_NETHER_BRICK_FENCE ) | |
( BlockInQuestion = = E_BLOCK_COBBLESTONE_WALL )
)
2013-09-15 10:55:35 -04:00
{
// Torches can be placed on tops of glass and fences, despite them being 'untorcheable'
// No need to check for upright orientation, it was done when the torch was placed
return true ;
}
2014-03-01 14:34:19 -05:00
else if ( ! cBlockInfo : : FullyOccupiesVoxel ( BlockInQuestion ) )
2013-09-15 10:55:35 -04:00
{
return false ;
}
else
{
return true ;
}
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 ) ) ;
}
virtual const char * GetStepSound ( void ) override
{
return " step.wood " ;
}
} ;