2013-07-29 07:13:03 -04:00
# pragma once
# include "ItemHandler.h"
# include "../World.h"
# include "../Simulator/FluidSimulator.h"
# include "../Blocks/BlockHandler.h"
2013-12-17 11:33:48 -05:00
# include "../LineBlockTracer.h"
2014-02-02 09:49:37 -05:00
# include "../BlockInServerPluginInterface.h"
2014-09-26 13:13:19 -04:00
# include "../Blocks/ChunkInterface.h"
2013-07-29 07:13:03 -04:00
class cItemBucketHandler :
public cItemHandler
{
public :
cItemBucketHandler ( int a_ItemType ) :
cItemHandler ( a_ItemType )
{
}
2015-04-14 04:49:01 -04:00
virtual bool OnItemUse (
cWorld * a_World , cPlayer * a_Player , cBlockPluginInterface & a_PluginInterface , const cItem & a_Item ,
int a_BlockX , int a_BlockY , int a_BlockZ , eBlockFace a_BlockFace
) override
2013-07-29 07:13:03 -04:00
{
switch ( m_ItemType )
{
2015-04-14 04:49:01 -04:00
case E_ITEM_BUCKET : return ScoopUpFluid ( a_World , a_Player , a_Item , a_BlockX , a_BlockY , a_BlockZ , a_BlockFace ) ;
case E_ITEM_LAVA_BUCKET : return PlaceFluid ( a_World , a_Player , a_PluginInterface , a_Item , a_BlockX , a_BlockY , a_BlockZ , a_BlockFace , E_BLOCK_LAVA ) ;
case E_ITEM_WATER_BUCKET : return PlaceFluid ( a_World , a_Player , a_PluginInterface , a_Item , a_BlockX , a_BlockY , a_BlockZ , a_BlockFace , E_BLOCK_WATER ) ;
2013-07-29 07:13:03 -04:00
default :
{
ASSERT ( ! " Unhandled ItemType " ) ;
return false ;
}
}
}
2016-02-05 16:45:45 -05:00
2015-04-14 04:55:48 -04:00
bool ScoopUpFluid ( cWorld * a_World , cPlayer * a_Player , const cItem & a_Item , int a_BlockX , int a_BlockY , int a_BlockZ , eBlockFace a_BlockFace )
2013-07-29 07:13:03 -04:00
{
2014-07-11 11:58:35 -04:00
if ( a_BlockFace ! = BLOCK_FACE_NONE )
2013-07-29 07:13:03 -04:00
{
return false ;
}
2013-12-17 11:33:48 -05:00
Vector3i BlockPos ;
2013-12-17 13:42:06 -05:00
if ( ! GetBlockFromTrace ( a_World , a_Player , BlockPos ) )
{
2014-07-17 16:15:34 -04:00
return false ; // Nothing in range.
2013-12-17 13:42:06 -05:00
}
2013-12-17 11:33:48 -05:00
if ( a_World - > GetBlockMeta ( BlockPos . x , BlockPos . y , BlockPos . z ) ! = 0 )
2013-07-29 07:13:03 -04:00
{
// Not a source block
return false ;
}
2013-12-17 11:33:48 -05:00
BLOCKTYPE Block = a_World - > GetBlock ( BlockPos . x , BlockPos . y , BlockPos . z ) ;
ENUM_ITEM_ID NewItem ;
if ( IsBlockWater ( Block ) )
2013-07-29 07:13:03 -04:00
{
2013-12-17 11:33:48 -05:00
NewItem = E_ITEM_WATER_BUCKET ;
2013-07-29 07:13:03 -04:00
}
2013-12-17 11:33:48 -05:00
else if ( IsBlockLava ( Block ) )
2013-07-29 07:13:03 -04:00
{
2013-12-17 11:33:48 -05:00
NewItem = E_ITEM_LAVA_BUCKET ;
}
else
{
return false ;
2013-07-29 07:13:03 -04:00
}
2016-02-05 16:45:45 -05:00
2015-05-21 13:03:51 -04:00
// Check to see if destination block is too far away
// Reach Distance Multiplayer = 5 Blocks
if ( ( BlockPos . x - a_Player - > GetPosX ( ) > 5 ) | | ( BlockPos . z - a_Player - > GetPosZ ( ) > 5 ) )
{
return false ;
}
2015-04-14 04:55:48 -04:00
// Remove water / lava block (unless plugins disagree)
if ( ! a_Player - > PlaceBlock ( BlockPos . x , BlockPos . y , BlockPos . z , E_BLOCK_AIR , 0 ) )
{
return false ;
}
2013-12-17 13:42:06 -05:00
// Give new bucket, filled with fluid when the gamemode is not creative:
if ( ! a_Player - > IsGameModeCreative ( ) )
2013-07-29 07:13:03 -04:00
{
2013-12-17 13:42:06 -05:00
// Remove the bucket from the inventory
if ( ! a_Player - > GetInventory ( ) . RemoveOneEquippedItem ( ) )
{
LOG ( " Clicked with an empty bucket, but cannot remove one from the inventory? WTF? " ) ;
ASSERT ( ! " Inventory bucket mismatch " ) ;
return true ;
}
2015-05-18 09:30:16 -04:00
if ( a_Player - > GetInventory ( ) . AddItem ( cItem ( NewItem ) ) ! = 1 )
2015-04-14 04:55:48 -04:00
{
// The bucket didn't fit, toss it as a pickup:
a_Player - > TossPickup ( cItem ( NewItem ) ) ;
}
2013-07-29 07:13:03 -04:00
}
return true ;
}
2015-04-14 04:49:01 -04:00
bool PlaceFluid (
cWorld * a_World , cPlayer * a_Player , cBlockPluginInterface & a_PluginInterface , const cItem & a_Item ,
int a_BlockX , int a_BlockY , int a_BlockZ , eBlockFace a_BlockFace , BLOCKTYPE a_FluidBlock
)
2014-07-17 16:59:02 -04:00
{
2014-07-11 11:58:35 -04:00
if ( a_BlockFace ! = BLOCK_FACE_NONE )
2013-07-29 07:13:03 -04:00
{
return false ;
}
2016-02-05 16:45:45 -05:00
2015-04-14 04:49:01 -04:00
BLOCKTYPE CurrentBlockType ;
NIBBLETYPE CurrentBlockMeta ;
eBlockFace EntryFace ;
2014-07-10 10:38:19 -04:00
Vector3i BlockPos ;
2015-04-14 04:49:01 -04:00
if ( ! GetPlacementCoordsFromTrace ( a_World , a_Player , BlockPos , CurrentBlockType , CurrentBlockMeta , EntryFace ) )
2014-07-10 10:38:19 -04:00
{
return false ;
}
2015-05-21 13:03:51 -04:00
// Check to see if destination block is too far away
// Reach Distance Multiplayer = 5 Blocks
if ( ( BlockPos . x - a_Player - > GetPosX ( ) > 5 ) | | ( BlockPos . z - a_Player - > GetPosZ ( ) > 5 ) )
{
return false ;
}
2016-02-05 16:45:45 -05:00
2013-07-29 07:13:03 -04:00
if ( a_Player - > GetGameMode ( ) ! = gmCreative )
{
// Remove fluid bucket, add empty bucket:
if ( ! a_Player - > GetInventory ( ) . RemoveOneEquippedItem ( ) )
{
LOG ( " Clicked with a full bucket, but cannot remove one from the inventory? WTF? " ) ;
ASSERT ( ! " Inventory bucket mismatch " ) ;
return false ;
}
cItem Item ( E_ITEM_BUCKET , 1 ) ;
2015-05-18 09:30:16 -04:00
if ( ! a_Player - > GetInventory ( ) . AddItem ( Item ) )
2013-07-29 07:13:03 -04:00
{
return false ;
}
}
2016-02-05 16:45:45 -05:00
2013-07-29 07:13:03 -04:00
// Wash away anything that was there prior to placing:
2015-04-14 04:49:01 -04:00
if ( cFluidSimulator : : CanWashAway ( CurrentBlockType ) )
2013-07-29 07:13:03 -04:00
{
2015-04-14 04:49:01 -04:00
if ( a_PluginInterface . CallHookPlayerBreakingBlock ( * a_Player , BlockPos . x , BlockPos . y , BlockPos . z , EntryFace , CurrentBlockType , CurrentBlockMeta ) )
{
// Plugin disagrees with the washing-away
return false ;
}
cBlockHandler * Handler = BlockHandler ( CurrentBlockType ) ;
2013-07-29 07:13:03 -04:00
if ( Handler - > DoesDropOnUnsuitable ( ) )
{
2014-02-02 09:49:37 -05:00
cChunkInterface ChunkInterface ( a_World - > GetChunkMap ( ) ) ;
2015-04-14 04:49:01 -04:00
Handler - > DropBlock ( ChunkInterface , * a_World , a_PluginInterface , a_Player , BlockPos . x , BlockPos . y , BlockPos . z ) ;
2013-07-29 07:13:03 -04:00
}
2015-04-14 04:49:01 -04:00
a_PluginInterface . CallHookPlayerBrokenBlock ( * a_Player , BlockPos . x , BlockPos . y , BlockPos . z , EntryFace , CurrentBlockType , CurrentBlockMeta ) ;
2013-07-29 07:13:03 -04:00
}
2015-04-14 04:49:01 -04:00
// Place the actual fluid block:
return a_Player - > PlaceBlock ( BlockPos . x , BlockPos . y , BlockPos . z , a_FluidBlock , 0 ) ;
2013-07-29 07:13:03 -04:00
}
2013-12-17 14:06:48 -05:00
2015-04-14 04:49:01 -04:00
2014-07-10 11:46:07 -04:00
bool GetBlockFromTrace ( cWorld * a_World , cPlayer * a_Player , Vector3i & a_BlockPos )
2013-12-17 11:33:48 -05:00
{
class cCallbacks :
public cBlockTracer : : cCallbacks
{
public :
2013-12-17 14:02:44 -05:00
Vector3i m_Pos ;
2013-12-17 14:06:48 -05:00
bool m_HasHitFluid ;
2016-02-05 16:45:45 -05:00
2013-12-17 14:06:48 -05:00
cCallbacks ( void ) :
m_HasHitFluid ( false )
{
}
2016-02-05 16:45:45 -05:00
2013-12-17 11:33:48 -05:00
virtual bool OnNextBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , char a_EntryFace ) override
{
2013-12-17 13:42:06 -05:00
if ( IsBlockWater ( a_BlockType ) | | IsBlockLava ( a_BlockType ) )
2013-12-17 11:33:48 -05:00
{
2014-07-17 16:15:34 -04:00
if ( a_BlockMeta ! = 0 ) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source
2014-03-23 18:32:45 -04:00
{
return false ;
}
2013-12-17 14:06:48 -05:00
m_HasHitFluid = true ;
m_Pos . Set ( a_BlockX , a_BlockY , a_BlockZ ) ;
2013-12-17 11:33:48 -05:00
return true ;
}
return false ;
}
} Callbacks ;
cLineBlockTracer Tracer ( * a_World , Callbacks ) ;
Vector3d Start ( a_Player - > GetEyePosition ( ) + a_Player - > GetLookVector ( ) ) ;
Vector3d End ( a_Player - > GetEyePosition ( ) + a_Player - > GetLookVector ( ) * 5 ) ;
Tracer . Trace ( Start . x , Start . y , Start . z , End . x , End . y , End . z ) ;
2013-12-17 14:06:48 -05:00
if ( ! Callbacks . m_HasHitFluid )
2013-12-17 13:42:06 -05:00
{
return false ;
}
2014-07-10 11:46:07 -04:00
a_BlockPos = Callbacks . m_Pos ;
2013-12-17 11:33:48 -05:00
return true ;
}
2016-02-05 16:45:45 -05:00
2015-04-14 04:49:01 -04:00
bool GetPlacementCoordsFromTrace ( cWorld * a_World , cPlayer * a_Player , Vector3i & a_BlockPos , BLOCKTYPE & a_BlockType , NIBBLETYPE & a_BlockMeta , eBlockFace & a_BlockFace )
2014-07-10 10:10:42 -04:00
{
class cCallbacks :
public cBlockTracer : : cCallbacks
{
public :
2014-07-10 11:46:07 -04:00
Vector3i m_Pos ;
2015-04-14 04:49:01 -04:00
BLOCKTYPE m_ReplacedBlockType ;
NIBBLETYPE m_ReplacedBlockMeta ;
eBlockFace m_EntryFace ;
2016-02-05 16:45:45 -05:00
2015-01-18 12:01:24 -05:00
virtual bool OnNextBlock ( int a_CBBlockX , int a_CBBlockY , int a_CBBlockZ , BLOCKTYPE a_CBBlockType , NIBBLETYPE a_CBBlockMeta , char a_CBEntryFace ) override
2014-07-10 10:10:42 -04:00
{
2015-01-18 12:01:24 -05:00
if ( a_CBBlockType ! = E_BLOCK_AIR )
2014-07-10 11:46:07 -04:00
{
2015-04-14 04:49:01 -04:00
m_ReplacedBlockType = a_CBBlockType ;
m_ReplacedBlockMeta = a_CBBlockMeta ;
m_EntryFace = static_cast < eBlockFace > ( a_CBEntryFace ) ;
2015-01-18 12:01:24 -05:00
if ( ! cFluidSimulator : : CanWashAway ( a_CBBlockType ) & & ! IsBlockLiquid ( a_CBBlockType ) )
2014-07-11 11:58:35 -04:00
{
2015-05-24 07:56:56 -04:00
AddFaceDirection ( a_CBBlockX , a_CBBlockY , a_CBBlockZ , static_cast < eBlockFace > ( a_CBEntryFace ) ) ; // Was an unwashawayable block, can't overwrite it!
2014-07-11 11:58:35 -04:00
}
2015-01-18 12:01:24 -05:00
m_Pos . Set ( a_CBBlockX , a_CBBlockY , a_CBBlockZ ) ; // (Block could be washed away, replace it)
2014-07-12 17:50:28 -04:00
return true ; // Abort tracing
2014-07-17 16:59:02 -04:00
}
2014-07-10 11:46:07 -04:00
return false ;
2014-07-10 10:10:42 -04:00
}
} Callbacks ;
2013-12-17 11:33:48 -05:00
2014-07-10 10:10:42 -04:00
cLineBlockTracer Tracer ( * a_World , Callbacks ) ;
2014-07-16 17:22:00 -04:00
Vector3d Start ( a_Player - > GetEyePosition ( ) ) ;
2014-07-17 16:59:02 -04:00
Vector3d End ( a_Player - > GetEyePosition ( ) + a_Player - > GetLookVector ( ) * 5 ) ;
2014-07-10 10:10:42 -04:00
2015-04-14 04:49:01 -04:00
// cTracer::Trace returns true when whole line was traversed. By returning true from the callback when we hit something, we ensure that this never happens if liquid could be placed
2014-07-12 17:50:28 -04:00
// Use this to judge whether the position is valid
if ( ! Tracer . Trace ( Start . x , Start . y , Start . z , End . x , End . y , End . z ) )
2014-07-10 10:10:42 -04:00
{
2014-07-12 17:50:28 -04:00
a_BlockPos = Callbacks . m_Pos ;
2015-04-14 04:49:01 -04:00
a_BlockType = Callbacks . m_ReplacedBlockType ;
a_BlockMeta = Callbacks . m_ReplacedBlockMeta ;
a_BlockFace = Callbacks . m_EntryFace ;
2014-07-12 17:50:28 -04:00
return true ;
2014-07-10 10:10:42 -04:00
}
2014-07-17 16:59:02 -04:00
return false ;
2014-07-10 10:10:42 -04:00
}
2013-07-29 07:13:03 -04:00
} ;