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 )
{
}
2014-02-04 13:59:05 -05:00
virtual bool OnItemUse ( cWorld * a_World , cPlayer * a_Player , const cItem & a_Item , int a_BlockX , int a_BlockY , int a_BlockZ , eBlockFace a_Dir ) override
2013-07-29 07:13:03 -04:00
{
switch ( m_ItemType )
{
case E_ITEM_BUCKET : return ScoopUpFluid ( a_World , a_Player , a_Item , a_BlockX , a_BlockY , a_BlockZ , a_Dir ) ;
case E_ITEM_LAVA_BUCKET : return PlaceFluid ( a_World , a_Player , a_Item , a_BlockX , a_BlockY , a_BlockZ , a_Dir , E_BLOCK_LAVA ) ;
case E_ITEM_WATER_BUCKET : return PlaceFluid ( a_World , a_Player , a_Item , a_BlockX , a_BlockY , a_BlockZ , a_Dir , E_BLOCK_WATER ) ;
default :
{
ASSERT ( ! " Unhandled ItemType " ) ;
return false ;
}
}
}
bool ScoopUpFluid ( cWorld * a_World , cPlayer * a_Player , const cItem & a_Item , int a_BlockX , int a_BlockY , int a_BlockZ , char a_BlockFace )
{
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
}
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 ;
}
a_Player - > GetInventory ( ) . AddItem ( cItem ( NewItem ) , true , true ) ;
2013-07-29 07:13:03 -04:00
}
// Remove water / lava block
2013-12-17 11:33:48 -05:00
a_Player - > GetWorld ( ) - > SetBlock ( BlockPos . x , BlockPos . y , BlockPos . z , E_BLOCK_AIR , 0 ) ;
2013-07-29 07:13:03 -04:00
return true ;
}
2014-02-04 13:59:05 -05:00
bool PlaceFluid ( cWorld * a_World , cPlayer * a_Player , 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 ;
}
2014-07-10 10:38:19 -04:00
2014-07-10 11:46:07 -04:00
BLOCKTYPE CurrentBlock ;
2014-07-10 10:38:19 -04:00
Vector3i BlockPos ;
2014-07-11 11:58:35 -04:00
if ( ! GetPlacementCoordsFromTrace ( a_World , a_Player , BlockPos , CurrentBlock ) )
2014-07-10 10:38:19 -04:00
{
return false ;
}
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 ) ;
2014-07-19 08:53:41 -04:00
if ( ! a_Player - > GetInventory ( ) . AddItem ( Item , true , true ) )
2013-07-29 07:13:03 -04:00
{
return false ;
}
}
// Wash away anything that was there prior to placing:
2014-07-12 06:44:59 -04:00
if ( cFluidSimulator : : CanWashAway ( CurrentBlock ) )
2013-07-29 07:13:03 -04:00
{
cBlockHandler * Handler = BlockHandler ( CurrentBlock ) ;
if ( Handler - > DoesDropOnUnsuitable ( ) )
{
2014-02-02 09:49:37 -05:00
cChunkInterface ChunkInterface ( a_World - > GetChunkMap ( ) ) ;
cBlockInServerPluginInterface PluginInterface ( * a_World ) ;
Handler - > DropBlock ( ChunkInterface , * a_World , PluginInterface , a_Player , a_BlockX , a_BlockY , a_BlockZ ) ;
2013-07-29 07:13:03 -04:00
}
}
2014-07-10 10:10:42 -04:00
a_World - > SetBlock ( BlockPos . x , BlockPos . y , BlockPos . z , a_FluidBlock , 0 ) ;
2013-07-29 07:13:03 -04:00
return true ;
}
2013-12-17 14:06:48 -05: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 ;
cCallbacks ( void ) :
m_HasHitFluid ( false )
{
}
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 ;
}
2014-07-12 06:44:59 -04:00
bool GetPlacementCoordsFromTrace ( cWorld * a_World , cPlayer * a_Player , Vector3i & a_BlockPos , BLOCKTYPE & a_BlockType )
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 ;
2014-07-12 17:50:28 -04:00
BLOCKTYPE m_ReplacedBlock ;
2014-07-10 10:10:42 -04:00
virtual bool OnNextBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , char a_EntryFace ) override
{
2014-07-10 11:46:07 -04:00
if ( a_BlockType ! = E_BLOCK_AIR )
{
2014-07-12 17:50:28 -04:00
m_ReplacedBlock = a_BlockType ;
2014-07-14 16:55:46 -04:00
if ( ! cFluidSimulator : : CanWashAway ( a_BlockType ) & & ! IsBlockLiquid ( a_BlockType ) )
2014-07-11 11:58:35 -04:00
{
2014-07-12 17:52:45 -04:00
AddFaceDirection ( a_BlockX , a_BlockY , a_BlockZ , ( eBlockFace ) a_EntryFace ) ; // Was an unwashawayable block, can't overwrite it!
2014-07-11 11:58:35 -04:00
}
2014-07-12 17:50:28 -04:00
m_Pos . Set ( a_BlockX , a_BlockY , a_BlockZ ) ; // (Block could be washed away, replace it)
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
2014-07-12 17:50:28 -04:00
// cTracer::Trace returns true when whole line was traversed. By returning true when we hit something, we ensure that this never happens if liquid could be placed
// 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 ;
a_BlockType = Callbacks . m_ReplacedBlock ;
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
} ;