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-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
{
2013-09-15 15:55:35 +01:00
// Find proper placement of torch
if (( a_BlockFace == BLOCK_FACE_TOP ) || ( a_BlockFace == BLOCK_FACE_BOTTOM ))
2013-07-29 12:13:03 +01:00
{
2014-07-17 22:15:34 +02:00
a_BlockFace = FindSuitableFace ( a_ChunkInterface , a_BlockX , a_BlockY , a_BlockZ ); // Top or bottom faces clicked, find a suitable face
2013-09-15 15:55:35 +01:00
if ( a_BlockFace == BLOCK_FACE_NONE )
2013-07-29 12:13:03 +01:00
{
2013-09-15 15:55:35 +01:00
// Client wouldn't have sent anything anyway, but whatever
2013-07-29 12:13:03 +01:00
return false ;
}
}
2013-09-15 15:55:35 +01:00
else
{
// Not top or bottom faces, try to preserve whatever face was clicked
2014-07-17 22:15:34 +02:00
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , a_BlockFace , true ); // Set to clicked block
2014-02-01 05:06:32 -08:00
if ( ! CanBePlacedOn ( a_ChunkInterface . GetBlock ( a_BlockX , a_BlockY , a_BlockZ ), a_BlockFace ))
2013-09-15 15:55:35 +01:00
{
2014-07-17 22:15:34 +02:00
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , a_BlockFace , false ); // Reset to torch block
2013-09-15 15:55:35 +01:00
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
2014-01-31 15:17:41 -08:00
a_BlockFace = FindSuitableFace ( a_ChunkInterface , a_BlockX , a_BlockY , a_BlockZ );
2013-09-15 15:55:35 +01:00
if ( a_BlockFace == BLOCK_FACE_NONE )
{
return false ;
}
}
}
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 ;
default :
{
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-02-04 10:59:05 -08:00
static bool CanBePlacedOn ( BLOCKTYPE a_BlockType , eBlockFace a_BlockFace )
2013-07-29 12:13:03 +01:00
{
2014-03-01 21:34:19 +02:00
if ( ! cBlockInfo :: FullyOccupiesVoxel ( a_BlockType ) )
2013-09-15 15:55:35 +01:00
{
2013-12-06 19:35:10 +00: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 15:21:31 +01:00
}
2013-09-15 15:55:35 +01:00
else
{
return true ;
2013-07-29 12:13:03 +01:00
}
}
2013-09-15 15:55:35 +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-02-01 05:06:32 -08:00
BLOCKTYPE BlockInQuestion = a_ChunkInterface . GetBlock ( a_BlockX , a_BlockY , a_BlockZ );
2013-09-15 15:55:35 +01:00
2014-07-17 22:15:34 +02:00
if ( // If on a block that can only hold a torch if torch is standing on it, return that face
2013-09-15 15:55:35 +01:00
(( BlockInQuestion == E_BLOCK_GLASS ) ||
( BlockInQuestion == E_BLOCK_FENCE ) ||
( BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE ) ||
( BlockInQuestion == E_BLOCK_COBBLESTONE_WALL )) &&
2014-02-04 11:26:39 -08:00
( Face == BLOCK_FACE_TOP )
2013-09-15 15:55:35 +01:00
)
{
2014-02-04 11:26:39 -08:00
return Face ;
2013-09-15 15:55:35 +01:00
}
2014-03-01 21:34:19 +02:00
else if ( cBlockInfo :: FullyOccupiesVoxel ( BlockInQuestion ) && ( i != BLOCK_FACE_BOTTOM ))
2013-07-29 12:13:03 +01:00
{
2013-12-06 19:35:10 +00: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 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 );
BLOCKTYPE BlockInQuestion ;
a_Chunk . UnboundedRelGetBlockType ( a_RelX , a_RelY , a_RelZ , BlockInQuestion );
2013-09-16 19:18:36 +01:00
if (
( BlockInQuestion == E_BLOCK_GLASS ) ||
2014-06-28 00:29:32 +01:00
( BlockInQuestion == E_BLOCK_STAINED_GLASS ) ||
2013-09-16 19:18:36 +01:00
( BlockInQuestion == E_BLOCK_FENCE ) ||
2014-06-28 00:29:32 +01:00
( BlockInQuestion == E_BLOCK_SOULSAND ) ||
( BlockInQuestion == E_BLOCK_MOB_SPAWNER ) ||
2014-07-17 22:15:34 +02:00
( BlockInQuestion == E_BLOCK_END_PORTAL_FRAME ) || // Actual vanilla behaviour
2013-09-16 19:18:36 +01:00
( BlockInQuestion == E_BLOCK_NETHER_BRICK_FENCE ) ||
( BlockInQuestion == E_BLOCK_COBBLESTONE_WALL )
)
2013-09-15 15:55:35 +01: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 21:34:19 +02:00
else if ( ! cBlockInfo :: FullyOccupiesVoxel ( BlockInQuestion ) )
2013-09-15 15:55:35 +01:00
{
return false ;
}
else
{
return true ;
}
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 ));
}
virtual const char * GetStepSound ( void ) override
{
return "step.wood" ;
}
} ;