2013-07-29 12:13:03 +01:00
#pragma once
#include "BlockHandler.h"
2014-02-01 06:01:13 -08:00
#include "../Chunk.h"
2014-10-25 21:54:00 +01:00
#include "ChunkInterface.h"
2014-03-25 17:26:13 -04:00
#include "MetaRotator.h"
2013-07-29 12:13:03 +01:00
class cBlockTorchHandler :
2014-03-25 17:26:13 -04:00
public cMetaRotator < cBlockHandler , 0x7 , 0x4 , 0x1 , 0x3 , 0x2 >
2013-07-29 12:13:03 +01: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 12:13:03 +01:00
{
}
virtual bool GetPlacementBlockTypeMeta (
2014-02-01 05:06:32 -08:00
cChunkInterface & a_ChunkInterface , cPlayer * a_Player ,
2014-07-17 22:50:58 +02:00
int a_BlockX , int a_BlockY , int a_BlockZ , eBlockFace a_BlockFace ,
2013-07-29 12:13:03 +01:00
int a_CursorX , int a_CursorY , int a_CursorZ ,
BLOCKTYPE & a_BlockType , NIBBLETYPE & a_BlockMeta
) override
{
2014-09-30 22:00:33 +01: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 15:55:35 +01:00
2014-09-30 22:00:33 +01:00
if ( ! CanBePlacedOn ( Block , Meta , a_BlockFace )) // Try to preserve original direction
2013-07-29 12:13:03 +01:00
{
2014-09-30 22:00:33 +01: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 15:55:35 +01:00
if ( a_BlockFace == BLOCK_FACE_NONE )
2013-07-29 12:13:03 +01:00
{
2014-10-03 21:38:23 +01:00
// No attachable face found - don't place the torch
2013-07-29 12:13:03 +01:00
return false ;
}
}
2013-09-15 15:55:35 +01:00
2013-07-29 12:13:03 +01:00
a_BlockType = m_BlockType ;
a_BlockMeta = DirectionToMetaData ( a_BlockFace );
return true ;
}
2014-02-04 10:59:05 -08:00
inline static NIBBLETYPE DirectionToMetaData ( eBlockFace a_Direction )
2013-12-06 19:23:27 +00:00
{
2013-07-29 12:13:03 +01: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 ;
2015-05-19 12:28:31 +01:00
case BLOCK_FACE_NONE :
2013-07-29 12:13:03 +01:00
{
ASSERT ( ! "Unhandled torch direction!" );
break ;
}
};
return 0x0 ;
2013-12-06 19:23:27 +00:00
}
2013-07-29 12:13:03 +01:00
2014-02-04 10:59:05 -08:00
inline static eBlockFace MetaDataToDirection ( NIBBLETYPE a_MetaData )
2013-12-06 19:24:45 +00:00
{
2013-07-29 12:13:03 +01:00
switch ( a_MetaData )
{
2013-12-06 19:24:45 +00:00
case 0 : return BLOCK_FACE_TOP ; // By default, the torches stand on the ground
2013-07-29 12:13:03 +01: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 10:59:05 -08:00
return BLOCK_FACE_TOP ;
2013-12-06 19:24:45 +00:00
}
2013-07-29 12:13:03 +01:00
2014-09-30 22:00:33 +01:00
static bool CanBePlacedOn ( BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , eBlockFace a_BlockFace )
2013-07-29 12:13:03 +01:00
{
2014-09-30 22:00:33 +01:00
switch ( a_BlockType )
2013-09-15 15:55:35 +01:00
{
2014-09-30 22:00:33 +01: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 23:18:21 +02: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 22:00:33 +01: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 :
{
// 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 21:38:23 +01:00
// Torches can be placed on all sides of full blocks except the bottom
2014-09-30 22:00:33 +01:00
return ( a_BlockFace != BLOCK_FACE_YM );
}
return false ;
}
2013-07-29 12:13:03 +01:00
}
}
2014-10-03 21:38:23 +01:00
/** Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure */
2014-02-04 10:59:05 -08:00
static eBlockFace FindSuitableFace ( cChunkInterface & a_ChunkInterface , int a_BlockX , int a_BlockY , int a_BlockZ )
2013-07-29 12:13:03 +01:00
{
2014-07-17 22:15:34 +02:00
for ( int i = BLOCK_FACE_YM ; i <= BLOCK_FACE_XP ; i ++ ) // Loop through all directions
2013-07-29 12:13:03 +01:00
{
2014-02-04 11:26:39 -08:00
eBlockFace Face = static_cast < eBlockFace > ( i );
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , Face , true );
2014-09-30 22:00:33 +01:00
BLOCKTYPE BlockInQuestion ;
NIBBLETYPE BlockInQuestionMeta ;
a_ChunkInterface . GetBlockTypeMeta ( a_BlockX , a_BlockY , a_BlockZ , BlockInQuestion , BlockInQuestionMeta );
if ( CanBePlacedOn ( BlockInQuestion , BlockInQuestionMeta , Face ))
2013-07-29 12:13:03 +01:00
{
2014-02-04 11:26:39 -08:00
return Face ;
2013-07-29 12:13:03 +01:00
}
2013-09-15 15:55:35 +01:00
else
{
2013-12-06 19:35:10 +00:00
// Reset coords in preparation for next iteration
2014-02-04 11:26:39 -08:00
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , Face , false );
2013-09-15 15:55:35 +01:00
}
2013-07-29 12:13:03 +01:00
}
2013-09-15 15:55:35 +01:00
return BLOCK_FACE_NONE ;
2013-07-29 12:13:03 +01:00
}
2014-02-01 05:06:32 -08:00
virtual bool CanBeAt ( cChunkInterface & a_ChunkInterface , int a_RelX , int a_RelY , int a_RelZ , const cChunk & a_Chunk ) override
2013-07-29 12:13:03 +01:00
{
2014-02-04 10:59:05 -08:00
eBlockFace Face = MetaDataToDirection ( a_Chunk . GetMeta ( a_RelX , a_RelY , a_RelZ ));
2013-09-15 15:55:35 +01:00
AddFaceDirection ( a_RelX , a_RelY , a_RelZ , Face , true );
2014-09-30 22:00:33 +01:00
2013-09-15 15:55:35 +01:00
BLOCKTYPE BlockInQuestion ;
2014-09-30 22:00:33 +01:00
NIBBLETYPE BlockInQuestionMeta ;
if ( ! a_Chunk . UnboundedRelGetBlock ( a_RelX , a_RelY , a_RelZ , BlockInQuestion , BlockInQuestionMeta ))
2013-09-15 15:55:35 +01:00
{
return false ;
}
2014-09-30 22:00:33 +01:00
return CanBePlacedOn ( BlockInQuestion , BlockInQuestionMeta , Face );
2013-07-29 12:13:03 +01:00
}
virtual void ConvertToPickups ( cItems & a_Pickups , NIBBLETYPE a_BlockMeta ) override
{
// Always drop meta = 0
a_Pickups . push_back ( cItem ( m_BlockType , 1 , 0 ));
}
} ;