2012-06-14 09:06:06 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 18:09:57 -04:00
# include "FurnaceEntity.h"
2013-05-28 15:12:47 -04:00
# include "../UI/Window.h"
2013-08-19 05:39:13 -04:00
# include "../Entities/Player.h"
2013-05-28 15:12:47 -04:00
# include "../Root.h"
2012-06-14 09:06:06 -04:00
2012-09-20 09:25:54 -04:00
enum
{
PROGRESSBAR_SMELTING = 0 ,
PROGRESSBAR_FUEL = 1 ,
} ;
2013-06-20 07:41:44 -04:00
cFurnaceEntity : : cFurnaceEntity ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , cWorld * a_World ) :
2013-06-16 16:24:07 -04:00
super ( E_BLOCK_FURNACE , a_BlockX , a_BlockY , a_BlockZ , ContentsWidth , ContentsHeight , a_World ) ,
2013-06-20 07:41:44 -04:00
m_BlockType ( a_BlockType ) ,
m_BlockMeta ( a_BlockMeta ) ,
2013-06-20 07:01:13 -04:00
m_CurrentRecipe ( NULL ) ,
2013-06-20 07:41:44 -04:00
m_IsCooking ( ( a_World - > GetBlock ( a_BlockX , a_BlockY , a_BlockZ ) = = E_BLOCK_LIT_FURNACE ) ) ,
2013-06-16 16:24:07 -04:00
m_NeedCookTime ( 0 ) ,
m_TimeCooked ( 0 ) ,
m_FuelBurnTime ( 0 ) ,
m_TimeBurned ( 0 ) ,
m_LastProgressFuel ( 0 ) ,
m_LastProgressCook ( 0 )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
m_Contents . AddListener ( * this ) ;
2012-06-14 09:06:06 -04:00
}
2013-06-16 16:24:07 -04:00
cFurnaceEntity : : ~ cFurnaceEntity ( )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
// Tell window its owner is destroyed
cWindow * Window = GetWindow ( ) ;
if ( Window ! = NULL )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
Window - > OwnerDestroyed ( ) ;
2012-06-14 09:06:06 -04:00
}
}
2012-09-20 09:25:54 -04:00
void cFurnaceEntity : : UsedBy ( cPlayer * a_Player )
2012-06-14 09:06:06 -04:00
{
2012-09-20 09:25:54 -04:00
if ( GetWindow ( ) = = NULL )
2012-06-14 09:06:06 -04:00
{
2012-09-20 09:25:54 -04:00
OpenWindow ( new cFurnaceWindow ( m_PosX , m_PosY , m_PosZ , this ) ) ;
2012-06-14 09:06:06 -04:00
}
2013-06-16 16:24:07 -04:00
cWindow * Window = GetWindow ( ) ;
if ( Window ! = NULL )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
if ( a_Player - > GetWindow ( ) ! = Window )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
a_Player - > OpenWindow ( Window ) ;
2014-10-11 22:39:55 -04:00
BroadcastProgress ( PROGRESSBAR_FUEL , static_cast < short > ( m_LastProgressFuel ) ) ;
BroadcastProgress ( PROGRESSBAR_SMELTING , static_cast < short > ( m_LastProgressCook ) ) ;
2012-06-14 09:06:06 -04:00
}
}
}
2013-06-16 16:24:07 -04:00
/// Restarts cooking. Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active. Returns true if cooking.
bool cFurnaceEntity : : ContinueCooking ( void )
{
UpdateInput ( ) ;
UpdateFuel ( ) ;
return m_IsCooking ;
}
2013-05-28 14:50:44 -04:00
bool cFurnaceEntity : : Tick ( float a_Dt , cChunk & a_Chunk )
2012-06-14 09:06:06 -04:00
{
2014-02-24 14:29:59 -05:00
UNUSED ( a_Dt ) ;
UNUSED ( a_Chunk ) ;
2013-06-16 16:24:07 -04:00
if ( m_FuelBurnTime < = 0 )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
// No fuel is burning, reset progressbars and bail out
if ( ( m_LastProgressCook > 0 ) | | ( m_LastProgressFuel > 0 ) )
2012-09-20 09:25:54 -04:00
{
2013-06-16 16:24:07 -04:00
UpdateProgressBars ( ) ;
2012-09-20 09:25:54 -04:00
}
2012-06-14 09:06:06 -04:00
return false ;
}
2013-06-16 16:24:07 -04:00
if ( m_IsCooking )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
m_TimeCooked + + ;
if ( m_TimeCooked > = m_NeedCookTime )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
// Finished smelting one item
2014-02-24 14:29:59 -05:00
FinishOne ( ) ;
2012-06-14 09:06:06 -04:00
}
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
m_TimeBurned + + ;
if ( m_TimeBurned > = m_FuelBurnTime )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
// The current fuel has been exhausted, use another one, if possible
BurnNewFuel ( ) ;
2012-06-14 09:06:06 -04:00
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
UpdateProgressBars ( ) ;
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
return true ;
2012-06-14 09:06:06 -04:00
}
2013-06-16 16:24:07 -04:00
void cFurnaceEntity : : SendTo ( cClientHandle & a_Client )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
// Nothing needs to be sent
UNUSED ( a_Client ) ;
2012-06-14 09:06:06 -04:00
}
2013-06-16 16:24:07 -04:00
void cFurnaceEntity : : BroadcastProgress ( int a_ProgressbarID , short a_Value )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
cWindow * Window = GetWindow ( ) ;
if ( Window ! = NULL )
2012-06-14 09:06:06 -04:00
{
2013-08-18 07:26:37 -04:00
Window - > BroadcastProgress ( a_ProgressbarID , a_Value ) ;
2012-06-14 09:06:06 -04:00
}
}
2013-06-16 16:24:07 -04:00
/// One item finished cooking
2014-02-24 14:29:59 -05:00
void cFurnaceEntity : : FinishOne ( )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
m_TimeCooked = 0 ;
2012-06-14 09:06:06 -04:00
2013-06-16 16:24:07 -04:00
if ( m_Contents . GetSlot ( fsOutput ) . IsEmpty ( ) )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
m_Contents . SetSlot ( fsOutput , * m_CurrentRecipe - > Out ) ;
}
else
{
m_Contents . ChangeSlotCount ( fsOutput , m_CurrentRecipe - > Out - > m_ItemCount ) ;
2012-06-14 09:06:06 -04:00
}
2013-06-16 16:24:07 -04:00
m_Contents . ChangeSlotCount ( fsInput , - m_CurrentRecipe - > In - > m_ItemCount ) ;
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
UpdateIsCooking ( ) ;
}
2012-06-14 09:06:06 -04:00
2013-06-16 16:24:07 -04:00
void cFurnaceEntity : : BurnNewFuel ( void )
{
cFurnaceRecipe * FR = cRoot : : Get ( ) - > GetFurnaceRecipe ( ) ;
int NewTime = FR - > GetBurnTime ( m_Contents . GetSlot ( fsFuel ) ) ;
if ( NewTime = = 0 )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
// The item in the fuel slot is not suitable
m_FuelBurnTime = 0 ;
m_TimeBurned = 0 ;
2013-06-20 07:41:44 -04:00
SetIsCooking ( false ) ;
2013-06-16 16:24:07 -04:00
return ;
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
// Is the input and output ready for cooking?
if ( ! CanCookInputToOutput ( ) )
{
return ;
}
// Burn one new fuel:
m_FuelBurnTime = NewTime ;
m_TimeBurned = 0 ;
2013-06-20 07:41:44 -04:00
SetIsCooking ( true ) ;
2013-06-16 16:24:07 -04:00
if ( m_Contents . GetSlot ( fsFuel ) . m_ItemType = = E_ITEM_LAVA_BUCKET )
{
m_Contents . SetSlot ( fsFuel , cItem ( E_ITEM_BUCKET ) ) ;
}
else
{
m_Contents . ChangeSlotCount ( fsFuel , - 1 ) ;
}
}
void cFurnaceEntity : : OnSlotChanged ( cItemGrid * a_ItemGrid , int a_SlotNum )
{
super : : OnSlotChanged ( a_ItemGrid , a_SlotNum ) ;
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
if ( m_World = = NULL )
{
// The furnace isn't initialized yet, do no processing
return ;
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
ASSERT ( a_ItemGrid = = & m_Contents ) ;
switch ( a_SlotNum )
{
case fsInput :
{
UpdateInput ( ) ;
break ;
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
case fsFuel :
{
UpdateFuel ( ) ;
break ;
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
case fsOutput :
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
UpdateOutput ( ) ;
break ;
2012-06-14 09:06:06 -04:00
}
}
2013-06-16 16:24:07 -04:00
}
2012-06-14 09:06:06 -04:00
2013-06-16 16:24:07 -04:00
/// Updates the current recipe, based on the current input
void cFurnaceEntity : : UpdateInput ( void )
{
2014-01-16 14:00:49 -05:00
if ( ! m_Contents . GetSlot ( fsInput ) . IsEqual ( m_LastInput ) )
2013-06-16 16:24:07 -04:00
{
// The input is different from what we had before, reset the cooking time
m_TimeCooked = 0 ;
}
m_LastInput = m_Contents . GetSlot ( fsInput ) ;
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
cFurnaceRecipe * FR = cRoot : : Get ( ) - > GetFurnaceRecipe ( ) ;
m_CurrentRecipe = FR - > GetRecipeFrom ( m_Contents . GetSlot ( fsInput ) ) ;
if ( ! CanCookInputToOutput ( ) )
{
// This input cannot be cooked
m_NeedCookTime = 0 ;
2013-06-20 07:41:44 -04:00
SetIsCooking ( false ) ;
2013-06-16 16:24:07 -04:00
}
else
{
m_NeedCookTime = m_CurrentRecipe - > CookTime ;
2013-06-20 07:41:44 -04:00
SetIsCooking ( true ) ;
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
// Start burning new fuel if there's no flame now:
if ( GetFuelBurnTimeLeft ( ) < = 0 )
{
BurnNewFuel ( ) ;
}
}
2012-06-14 09:06:06 -04:00
}
2013-06-16 16:24:07 -04:00
/// Called when the fuel slot changes or when the fuel is spent, burns another piece of fuel if appropriate
void cFurnaceEntity : : UpdateFuel ( void )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
if ( m_FuelBurnTime > m_TimeBurned )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
// The current fuel is still burning, don't modify anything:
return ;
2012-06-14 09:06:06 -04:00
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
// The current fuel is spent, try to burn some more:
BurnNewFuel ( ) ;
}
2012-06-14 09:06:06 -04:00
2013-06-16 16:24:07 -04:00
/// Called when the output slot changes; starts burning if space became available
void cFurnaceEntity : : UpdateOutput ( void )
{
if ( ! CanCookInputToOutput ( ) )
2012-06-14 09:06:06 -04:00
{
2013-06-16 16:24:07 -04:00
// Cannot cook anymore:
m_TimeCooked = 0 ;
m_NeedCookTime = 0 ;
2013-06-20 07:41:44 -04:00
SetIsCooking ( false ) ;
2013-06-16 16:24:07 -04:00
return ;
2012-06-14 09:06:06 -04:00
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
// No need to burn new fuel, the Tick() function will take care of that
2012-06-14 09:06:06 -04:00
2013-06-16 16:24:07 -04:00
// Can cook, start cooking if not already underway:
m_NeedCookTime = m_CurrentRecipe - > CookTime ;
2013-06-20 07:41:44 -04:00
SetIsCooking ( m_FuelBurnTime > 0 ) ;
2012-06-14 09:06:06 -04:00
}
2012-08-24 03:58:26 -04:00
2013-06-16 16:24:07 -04:00
/// Updates the m_IsCooking, based on the input slot, output slot and m_FuelBurnTime / m_TimeBurned
void cFurnaceEntity : : UpdateIsCooking ( void )
2012-08-24 03:58:26 -04:00
{
2013-06-16 16:24:07 -04:00
if (
! CanCookInputToOutput ( ) | | // Cannot cook this
( m_FuelBurnTime < = 0 ) | | // No fuel
( m_TimeBurned > = m_FuelBurnTime ) // Fuel burnt out
)
{
// Reset everything
2013-06-20 07:41:44 -04:00
SetIsCooking ( false ) ;
2013-06-16 16:24:07 -04:00
m_TimeCooked = 0 ;
m_NeedCookTime = 0 ;
return ;
}
2014-10-11 22:39:55 -04:00
2013-06-20 07:41:44 -04:00
SetIsCooking ( true ) ;
2012-08-24 03:58:26 -04:00
}
2012-09-20 09:25:54 -04:00
2013-06-16 16:24:07 -04:00
/// Returns true if the input can be cooked into output and the item counts allow for another cooking operation
bool cFurnaceEntity : : CanCookInputToOutput ( void ) const
2012-09-20 09:25:54 -04:00
{
2013-06-16 16:24:07 -04:00
if ( m_CurrentRecipe = = NULL )
2012-09-20 09:25:54 -04:00
{
2013-06-16 16:24:07 -04:00
// This input cannot be cooked
return false ;
}
2014-10-11 22:39:55 -04:00
2014-04-18 15:09:44 -04:00
const cItem & Slot = m_Contents . GetSlot ( fsOutput ) ;
if ( Slot . IsEmpty ( ) )
2013-06-16 16:24:07 -04:00
{
// The output is empty, can cook
return true ;
}
2014-04-18 15:09:44 -04:00
if ( ! Slot . IsEqual ( * m_CurrentRecipe - > Out ) )
2013-06-16 16:24:07 -04:00
{
// The output slot is blocked with something that cannot be stacked with the recipe's output
return false ;
}
2014-10-11 22:39:55 -04:00
2014-04-18 15:09:44 -04:00
if ( Slot . IsFullStack ( ) )
2013-06-16 16:24:07 -04:00
{
// Cannot add any more items to the output slot
return false ;
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
return true ;
}
/// Broadcasts progressbar updates, if needed
void cFurnaceEntity : : UpdateProgressBars ( void )
{
// In order to preserve bandwidth, an update is sent only every 10th tick
// That's why the comparisons use the division by eight
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
int CurFuel = ( m_FuelBurnTime > 0 ) ? ( 200 - 200 * m_TimeBurned / m_FuelBurnTime ) : 0 ;
if ( ( CurFuel / 8 ) ! = ( m_LastProgressFuel / 8 ) )
{
2014-10-11 22:39:55 -04:00
BroadcastProgress ( PROGRESSBAR_FUEL , static_cast < short > ( CurFuel ) ) ;
2013-06-16 16:24:07 -04:00
m_LastProgressFuel = CurFuel ;
}
2014-10-11 22:39:55 -04:00
2013-06-16 16:24:07 -04:00
int CurCook = ( m_NeedCookTime > 0 ) ? ( 200 * m_TimeCooked / m_NeedCookTime ) : 0 ;
if ( ( CurCook / 8 ) ! = ( m_LastProgressCook / 8 ) )
{
2014-10-11 22:39:55 -04:00
BroadcastProgress ( PROGRESSBAR_SMELTING , static_cast < short > ( CurCook ) ) ;
2013-06-16 16:24:07 -04:00
m_LastProgressCook = CurCook ;
2012-09-20 09:25:54 -04:00
}
}
2013-06-20 07:41:44 -04:00
void cFurnaceEntity : : SetIsCooking ( bool a_IsCooking )
{
if ( a_IsCooking = = m_IsCooking )
{
return ;
}
m_IsCooking = a_IsCooking ;
2014-10-11 22:39:55 -04:00
2013-06-20 07:41:44 -04:00
// Light or extinguish the furnace:
m_World - > FastSetBlock ( m_PosX , m_PosY , m_PosZ , m_IsCooking ? E_BLOCK_LIT_FURNACE : E_BLOCK_FURNACE , m_BlockMeta ) ;
}