2012-09-20 09:25:54 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 13:19:34 -04:00
# include "Window.h"
2013-05-28 15:12:47 -04:00
# include "WindowOwner.h"
# include "SlotArea.h"
2012-09-23 18:09:57 -04:00
# include "../Item.h"
# include "../ClientHandle.h"
2013-08-19 05:39:13 -04:00
# include "../Entities/Player.h"
# include "../Entities/Pickup.h"
2012-09-23 18:09:57 -04:00
# include "../Inventory.h"
2012-09-29 09:59:32 -04:00
# include "../Items/ItemHandler.h"
2013-05-28 15:12:47 -04:00
# include "../BlockEntities/ChestEntity.h"
2013-06-16 16:24:07 -04:00
# include "../BlockEntities/DropSpenserEntity.h"
2013-06-13 03:36:43 -04:00
# include "../BlockEntities/HopperEntity.h"
2012-09-20 09:25:54 -04:00
char cWindow : : m_WindowIDCounter = 1 ;
2013-10-28 08:30:24 -04:00
cWindow : : cWindow ( WindowType a_WindowType , const AString & a_WindowTitle ) :
2013-05-30 04:40:13 -04:00
m_WindowID ( ( + + m_WindowIDCounter ) % 127 ) ,
m_WindowType ( a_WindowType ) ,
m_WindowTitle ( a_WindowTitle ) ,
m_Owner ( NULL ) ,
m_IsDestroyed ( false ) ,
m_ShouldDistributeToHotbarFirst ( true )
2012-09-20 09:25:54 -04:00
{
2013-10-28 08:30:24 -04:00
if ( a_WindowType = = wtInventory )
2012-09-20 09:25:54 -04:00
{
m_WindowID = 0 ;
}
}
cWindow : : ~ cWindow ( )
{
2012-09-29 15:55:18 -04:00
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
delete * itr ;
}
m_SlotAreas . clear ( ) ;
2012-09-20 09:25:54 -04:00
}
int cWindow : : GetNumSlots ( void ) const
{
int res = 0 ;
for ( cSlotAreas : : const_iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
res + = ( * itr ) - > GetNumSlots ( ) ;
} // for itr - m_SlotAreas[]
return res ;
}
2013-05-30 04:40:13 -04:00
const cItem * cWindow : : GetSlot ( cPlayer & a_Player , int a_SlotNum ) const
{
// Return the item at the specified slot for the specified player
int LocalSlotNum = 0 ;
const cSlotArea * Area = GetSlotArea ( a_SlotNum , LocalSlotNum ) ;
if ( Area = = NULL )
{
LOGWARNING ( " %s: requesting item from an invalid SlotArea (SlotNum %d), returning NULL. " , __FUNCTION__ , a_SlotNum ) ;
return NULL ;
}
return Area - > GetSlot ( LocalSlotNum , a_Player ) ;
}
void cWindow : : SetSlot ( cPlayer & a_Player , int a_SlotNum , const cItem & a_Item )
{
// Set the item to the specified slot for the specified player
int LocalSlotNum = 0 ;
cSlotArea * Area = GetSlotArea ( a_SlotNum , LocalSlotNum ) ;
if ( Area = = NULL )
{
LOGWARNING ( " %s: requesting write to an invalid SlotArea (SlotNum %d), ignoring. " , __FUNCTION__ , a_SlotNum ) ;
return ;
}
Area - > SetSlot ( LocalSlotNum , a_Player , a_Item ) ;
}
2013-05-30 15:34:09 -04:00
bool cWindow : : IsSlotInPlayerMainInventory ( int a_SlotNum ) const
{
// Returns true if the specified slot is in the Player Main Inventory slotarea
// The player main inventory is always 27 slots, 9 slots from the end of the inventory
return ( ( a_SlotNum > = GetNumSlots ( ) - 36 ) & & ( a_SlotNum < GetNumSlots ( ) - 9 ) ) ;
}
bool cWindow : : IsSlotInPlayerHotbar ( int a_SlotNum ) const
{
// Returns true if the specified slot is in the Player Hotbar slotarea
// The hotbar is always the last 9 slots
return ( ( a_SlotNum > = GetNumSlots ( ) - 9 ) & & ( a_SlotNum < GetNumSlots ( ) ) ) ;
}
bool cWindow : : IsSlotInPlayerInventory ( int a_SlotNum ) const
{
// Returns true if the specified slot is in the Player Main Inventory or Hotbar slotareas. Note that returns false for Armor.
// The player combined inventory is always the last 36 slots
return ( ( a_SlotNum > = GetNumSlots ( ) - 36 ) & & ( a_SlotNum < GetNumSlots ( ) ) ) ;
}
2012-09-20 09:25:54 -04:00
void cWindow : : GetSlots ( cPlayer & a_Player , cItems & a_Slots ) const
{
a_Slots . clear ( ) ;
a_Slots . reserve ( GetNumSlots ( ) ) ;
for ( cSlotAreas : : const_iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
int NumSlots = ( * itr ) - > GetNumSlots ( ) ;
for ( int i = 0 ; i < NumSlots ; i + + )
{
const cItem * Item = ( * itr ) - > GetSlot ( i , a_Player ) ;
if ( Item = = NULL )
{
a_Slots . push_back ( cItem ( ) ) ;
}
else
{
a_Slots . push_back ( * Item ) ;
}
}
} // for itr - m_SlotAreas[]
}
void cWindow : : Clicked (
cPlayer & a_Player ,
2013-05-08 05:45:07 -04:00
int a_WindowID , short a_SlotNum , eClickAction a_ClickAction ,
2012-09-20 09:25:54 -04:00
const cItem & a_ClickedItem
)
{
if ( a_WindowID ! = m_WindowID )
{
2013-05-30 04:40:13 -04:00
LOGWARNING ( " %s: Wrong window ID (exp %d, got %d) received from \" %s \" ; ignoring click. " , __FUNCTION__ , m_WindowID , a_WindowID , a_Player . GetName ( ) . c_str ( ) ) ;
2012-09-20 09:25:54 -04:00
return ;
}
2013-05-08 05:45:07 -04:00
switch ( a_ClickAction )
2012-09-20 09:25:54 -04:00
{
2013-05-08 05:45:07 -04:00
case caRightClickOutside :
2012-09-20 09:25:54 -04:00
{
2013-05-08 05:45:07 -04:00
// Toss one of the dragged items:
2012-09-20 09:25:54 -04:00
a_Player . TossItem ( true ) ;
2013-05-08 05:45:07 -04:00
return ;
2012-09-20 09:25:54 -04:00
}
2013-05-08 05:45:07 -04:00
case caLeftClickOutside :
2012-09-20 09:25:54 -04:00
{
2013-05-08 05:45:07 -04:00
// Toss all dragged items:
2012-09-20 09:25:54 -04:00
a_Player . TossItem ( true , a_Player . GetDraggingItem ( ) . m_ItemCount ) ;
2013-05-08 05:45:07 -04:00
return ;
}
case caLeftClickOutsideHoldNothing :
case caRightClickOutsideHoldNothing :
{
// Nothing needed
return ;
2012-09-20 09:25:54 -04:00
}
2013-05-30 04:40:13 -04:00
case caLeftPaintBegin : OnPaintBegin ( a_Player ) ; return ;
case caRightPaintBegin : OnPaintBegin ( a_Player ) ; return ;
case caLeftPaintProgress : OnPaintProgress ( a_Player , a_SlotNum ) ; return ;
case caRightPaintProgress : OnPaintProgress ( a_Player , a_SlotNum ) ; return ;
case caLeftPaintEnd : OnLeftPaintEnd ( a_Player ) ; return ;
case caRightPaintEnd : OnRightPaintEnd ( a_Player ) ; return ;
2013-05-08 05:45:07 -04:00
}
if ( a_SlotNum < 0 )
{
// TODO: Other click actions with irrelevant slot number (FS #371)
2012-09-20 09:25:54 -04:00
return ;
}
int LocalSlotNum = a_SlotNum ;
int idx = 0 ;
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
if ( LocalSlotNum < ( * itr ) - > GetNumSlots ( ) )
{
2013-05-08 05:45:07 -04:00
( * itr ) - > Clicked ( a_Player , LocalSlotNum , a_ClickAction , a_ClickedItem ) ;
2012-09-20 09:25:54 -04:00
return ;
}
LocalSlotNum - = ( * itr ) - > GetNumSlots ( ) ;
idx + + ;
}
LOGWARNING ( " Slot number higher than available window slots: %d, max %d received from \" %s \" ; ignoring. " ,
a_SlotNum , GetNumSlots ( ) , a_Player . GetName ( ) . c_str ( )
) ;
}
void cWindow : : OpenedByPlayer ( cPlayer & a_Player )
{
{
cCSLock Lock ( m_CS ) ;
// If player is already in OpenedBy remove player first
m_OpenedBy . remove ( & a_Player ) ;
// Then add player
m_OpenedBy . push_back ( & a_Player ) ;
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
( * itr ) - > OnPlayerAdded ( a_Player ) ;
} // for itr - m_SlotAreas[]
}
a_Player . GetClientHandle ( ) - > SendWindowOpen ( m_WindowID , m_WindowType , m_WindowTitle , GetNumSlots ( ) - c_NumInventorySlots ) ;
}
2013-06-02 17:59:25 -04:00
bool cWindow : : ClosedByPlayer ( cPlayer & a_Player , bool a_CanRefuse )
2012-09-20 09:25:54 -04:00
{
// Checks whether the player is still holding an item
if ( a_Player . IsDraggingItem ( ) )
{
LOGD ( " Player holds item! Dropping it... " ) ;
a_Player . TossItem ( true , a_Player . GetDraggingItem ( ) . m_ItemCount ) ;
}
cClientHandle * ClientHandle = a_Player . GetClientHandle ( ) ;
if ( ClientHandle ! = NULL )
{
2013-04-04 07:47:31 -04:00
ClientHandle - > SendWindowClose ( * this ) ;
2012-09-20 09:25:54 -04:00
}
{
cCSLock Lock ( m_CS ) ;
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
( * itr ) - > OnPlayerRemoved ( a_Player ) ;
} // for itr - m_SlotAreas[]
m_OpenedBy . remove ( & a_Player ) ;
2013-04-04 07:47:31 -04:00
2013-10-28 08:30:24 -04:00
if ( ( m_WindowType ! = wtInventory ) & & m_OpenedBy . empty ( ) )
2012-09-20 09:25:54 -04:00
{
Destroy ( ) ;
}
}
if ( m_IsDestroyed )
{
delete this ;
}
2013-05-30 16:40:43 -04:00
return true ;
2012-09-20 09:25:54 -04:00
}
void cWindow : : OwnerDestroyed ( )
{
m_Owner = NULL ;
// Close window for each player. Note that the last one needs special handling
while ( m_OpenedBy . size ( ) > 1 )
{
2013-05-30 15:34:09 -04:00
( * m_OpenedBy . begin ( ) ) - > CloseWindow ( ) ;
2012-09-20 09:25:54 -04:00
}
2013-05-30 15:34:09 -04:00
( * m_OpenedBy . begin ( ) ) - > CloseWindow ( ) ;
2012-09-20 09:25:54 -04:00
}
bool cWindow : : ForEachPlayer ( cItemCallback < cPlayer > & a_Callback )
{
cCSLock Lock ( m_CS ) ;
for ( cPlayerList : : iterator itr = m_OpenedBy . begin ( ) , end = m_OpenedBy . end ( ) ; itr ! = end ; + + itr )
{
if ( a_Callback . Item ( * itr ) )
{
return false ;
}
} // for itr - m_OpenedBy[]
return true ;
}
bool cWindow : : ForEachClient ( cItemCallback < cClientHandle > & a_Callback )
{
cCSLock Lock ( m_CS ) ;
for ( cPlayerList : : iterator itr = m_OpenedBy . begin ( ) , end = m_OpenedBy . end ( ) ; itr ! = end ; + + itr )
{
if ( a_Callback . Item ( ( * itr ) - > GetClientHandle ( ) ) )
{
return false ;
}
} // for itr - m_OpenedBy[]
return true ;
}
2012-09-20 16:10:46 -04:00
void cWindow : : DistributeStack ( cItem & a_ItemStack , cPlayer & a_Player , cSlotArea * a_ExcludeArea , bool a_ShouldApply )
{
// Ask each slot area to take as much of the stack as it can.
// First ask only slots that already have the same kind of item
// Then ask any remaining slots
for ( int Pass = 0 ; Pass < 2 ; + + Pass )
{
2013-01-08 00:01:06 -05:00
if ( m_ShouldDistributeToHotbarFirst )
2012-09-20 16:10:46 -04:00
{
2013-01-08 00:01:06 -05:00
// First distribute into the hotbar:
if ( a_ExcludeArea ! = m_SlotAreas . back ( ) )
2012-09-20 16:10:46 -04:00
{
2013-01-08 00:01:06 -05:00
m_SlotAreas . back ( ) - > DistributeStack ( a_ItemStack , a_Player , a_ShouldApply , ( Pass = = 0 ) ) ;
if ( a_ItemStack . IsEmpty ( ) )
{
// Distributed it all
return ;
}
2012-09-20 16:10:46 -04:00
}
}
2013-01-08 00:01:06 -05:00
2012-09-20 16:10:46 -04:00
// The distribute to all other areas:
2013-01-08 00:01:06 -05:00
cSlotAreas : : iterator end = m_ShouldDistributeToHotbarFirst ? ( m_SlotAreas . end ( ) - 1 ) : m_SlotAreas . end ( ) ;
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) ; itr ! = end ; + + itr )
2012-09-20 16:10:46 -04:00
{
if ( * itr = = a_ExcludeArea )
{
continue ;
}
( * itr ) - > DistributeStack ( a_ItemStack , a_Player , a_ShouldApply , ( Pass = = 0 ) ) ;
if ( a_ItemStack . IsEmpty ( ) )
{
// Distributed it all
return ;
}
} // for itr - m_SlotAreas[]
} // for Pass - repeat twice
}
2012-09-21 16:50:34 -04:00
void cWindow : : SendSlot ( cPlayer & a_Player , cSlotArea * a_SlotArea , int a_RelativeSlotNum )
{
int SlotBase = 0 ;
bool Found = false ;
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
if ( * itr = = a_SlotArea )
{
Found = true ;
break ;
}
SlotBase + = ( * itr ) - > GetNumSlots ( ) ;
} // for itr - m_SlotAreas[]
if ( ! Found )
{
LOGERROR ( " cWindow::SendSlot(): unknown a_SlotArea " ) ;
ASSERT ( ! " cWindow::SendSlot(): unknown a_SlotArea " ) ;
return ;
}
a_Player . GetClientHandle ( ) - > SendInventorySlot (
m_WindowID , a_RelativeSlotNum + SlotBase , * ( a_SlotArea - > GetSlot ( a_RelativeSlotNum , a_Player ) )
) ;
}
2012-09-20 16:10:46 -04:00
void cWindow : : Destroy ( void )
2012-09-20 09:25:54 -04:00
{
if ( m_Owner ! = NULL )
{
m_Owner - > CloseWindow ( ) ;
m_Owner = NULL ;
}
m_IsDestroyed = true ;
}
2013-05-30 04:40:13 -04:00
cSlotArea * cWindow : : GetSlotArea ( int a_GlobalSlotNum , int & a_LocalSlotNum )
{
if ( ( a_GlobalSlotNum < 0 ) | | ( a_GlobalSlotNum > = GetNumSlots ( ) ) )
{
LOGWARNING ( " %s: requesting an invalid SlotNum: %d out of %d slots " , __FUNCTION__ , a_GlobalSlotNum , GetNumSlots ( ) - 1 ) ;
ASSERT ( ! " Invalid SlotNum " ) ;
return NULL ;
}
// Iterate through all the SlotAreas, find the correct one
int LocalSlotNum = a_GlobalSlotNum ;
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
if ( LocalSlotNum < ( * itr ) - > GetNumSlots ( ) )
{
a_LocalSlotNum = LocalSlotNum ;
return * itr ;
}
LocalSlotNum - = ( * itr ) - > GetNumSlots ( ) ;
} // for itr - m_SlotAreas[]
// We shouldn't be here - the check at the beginnning should prevent this. Log and assert
LOGWARNING ( " %s: GetNumSlots() is out of sync: %d; LocalSlotNum = %d " , __FUNCTION__ , GetNumSlots ( ) , LocalSlotNum ) ;
ASSERT ( ! " Invalid GetNumSlots " ) ;
return NULL ;
}
const cSlotArea * cWindow : : GetSlotArea ( int a_GlobalSlotNum , int & a_LocalSlotNum ) const
{
if ( ( a_GlobalSlotNum < 0 ) | | ( a_GlobalSlotNum > = GetNumSlots ( ) ) )
{
LOGWARNING ( " %s: requesting an invalid SlotNum: %d out of %d slots " , __FUNCTION__ , a_GlobalSlotNum , GetNumSlots ( ) - 1 ) ;
ASSERT ( ! " Invalid SlotNum " ) ;
return NULL ;
}
// Iterate through all the SlotAreas, find the correct one
int LocalSlotNum = a_GlobalSlotNum ;
for ( cSlotAreas : : const_iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
if ( LocalSlotNum < ( * itr ) - > GetNumSlots ( ) )
{
a_LocalSlotNum = LocalSlotNum ;
return * itr ;
}
LocalSlotNum - = ( * itr ) - > GetNumSlots ( ) ;
} // for itr - m_SlotAreas[]
// We shouldn't be here - the check at the beginnning should prevent this. Log and assert
LOGWARNING ( " %s: GetNumSlots() is out of sync: %d; LocalSlotNum = %d " , __FUNCTION__ , GetNumSlots ( ) , LocalSlotNum ) ;
ASSERT ( ! " Invalid GetNumSlots " ) ;
return NULL ;
}
void cWindow : : OnPaintBegin ( cPlayer & a_Player )
{
// Prepares the internal structures for inventory painting from the specified player
a_Player . ClearInventoryPaintSlots ( ) ;
}
void cWindow : : OnPaintProgress ( cPlayer & a_Player , int a_SlotNum )
{
// Add the slot to the internal structures for inventory painting by the specified player
a_Player . AddInventoryPaintSlot ( a_SlotNum ) ;
}
void cWindow : : OnLeftPaintEnd ( cPlayer & a_Player )
{
// Process the entire action stored in the internal structures for inventory painting
// distribute as many items as possible
const cSlotNums & SlotNums = a_Player . GetInventoryPaintSlots ( ) ;
cItem ToDistribute ( a_Player . GetDraggingItem ( ) ) ;
2013-05-30 06:10:58 -04:00
int ToEachSlot = ( int ) ToDistribute . m_ItemCount / SlotNums . size ( ) ;
int NumDistributed = DistributeItemToSlots ( a_Player , ToDistribute , ToEachSlot , SlotNums ) ;
// Remove the items distributed from the dragging item:
a_Player . GetDraggingItem ( ) . m_ItemCount - = NumDistributed ;
if ( a_Player . GetDraggingItem ( ) . m_ItemCount = = 0 )
{
a_Player . GetDraggingItem ( ) . Empty ( ) ;
}
SendWholeWindow ( * a_Player . GetClientHandle ( ) ) ;
}
void cWindow : : OnRightPaintEnd ( cPlayer & a_Player )
{
// Process the entire action stored in the internal structures for inventory painting
// distribute one item into each slot
const cSlotNums & SlotNums = a_Player . GetInventoryPaintSlots ( ) ;
cItem ToDistribute ( a_Player . GetDraggingItem ( ) ) ;
int NumDistributed = DistributeItemToSlots ( a_Player , ToDistribute , 1 , SlotNums ) ;
// Remove the items distributed from the dragging item:
a_Player . GetDraggingItem ( ) . m_ItemCount - = NumDistributed ;
if ( a_Player . GetDraggingItem ( ) . m_ItemCount = = 0 )
{
a_Player . GetDraggingItem ( ) . Empty ( ) ;
}
2013-05-30 04:40:13 -04:00
2013-05-30 06:10:58 -04:00
SendWholeWindow ( * a_Player . GetClientHandle ( ) ) ;
}
int cWindow : : DistributeItemToSlots ( cPlayer & a_Player , const cItem & a_Item , int a_NumToEachSlot , const cSlotNums & a_SlotNums )
{
if ( ( size_t ) ( a_Item . m_ItemCount ) < a_SlotNums . size ( ) )
2013-05-30 04:40:13 -04:00
{
2013-05-30 06:10:58 -04:00
LOGWARNING ( " %s: Distributing less items (%d) than slots (%u) " , __FUNCTION__ , ( int ) a_Item . m_ItemCount , a_SlotNums . size ( ) ) ;
2013-05-30 04:40:13 -04:00
// This doesn't seem to happen with the 1.5.1 client, so we don't worry about it for now
2013-05-30 06:10:58 -04:00
return 0 ;
2013-05-30 04:40:13 -04:00
}
// Distribute to individual slots, keep track of how many items were actually distributed (full stacks etc.)
int NumDistributed = 0 ;
2013-05-30 06:10:58 -04:00
for ( cSlotNums : : const_iterator itr = a_SlotNums . begin ( ) , end = a_SlotNums . end ( ) ; itr ! = end ; + + itr )
2013-05-30 04:40:13 -04:00
{
int LocalSlotNum = 0 ;
cSlotArea * Area = GetSlotArea ( * itr , LocalSlotNum ) ;
if ( Area = = NULL )
{
LOGWARNING ( " %s: Bad SlotArea for slot %d " , __FUNCTION__ , * itr ) ;
continue ;
}
// Modify the item at the slot
cItem AtSlot ( * Area - > GetSlot ( LocalSlotNum , a_Player ) ) ;
int MaxStack = ItemHandler ( AtSlot . m_ItemType ) - > GetMaxStackSize ( ) ;
if ( AtSlot . IsEmpty ( ) )
{
// Empty, just move all of it there:
2013-05-30 06:10:58 -04:00
cItem ToStore ( a_Item ) ;
ToStore . m_ItemCount = std : : min ( a_NumToEachSlot , ( int ) MaxStack ) ;
2013-05-30 04:40:13 -04:00
Area - > SetSlot ( LocalSlotNum , a_Player , ToStore ) ;
NumDistributed + = ToStore . m_ItemCount ;
}
else
{
2013-05-30 06:10:58 -04:00
// Occupied, add and cap at MaxStack:
int CanStore = std : : min ( a_NumToEachSlot , ( int ) MaxStack - AtSlot . m_ItemCount ) ;
2013-05-30 04:40:13 -04:00
AtSlot . m_ItemCount + = CanStore ;
Area - > SetSlot ( LocalSlotNum , a_Player , AtSlot ) ;
NumDistributed + = CanStore ;
}
} // for itr - SlotNums[]
2013-05-30 06:10:58 -04:00
return NumDistributed ;
2013-05-30 04:40:13 -04:00
}
2013-06-13 03:36:43 -04:00
void cWindow : : BroadcastSlot ( cSlotArea * a_Area , int a_LocalSlotNum )
{
// Translate local slot num into global slot num:
int SlotNum = 0 ;
bool HasFound = false ;
for ( cSlotAreas : : const_iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
if ( a_Area = = * itr )
{
SlotNum + = a_LocalSlotNum ;
HasFound = true ;
break ;
}
SlotNum + = ( * itr ) - > GetNumSlots ( ) ;
} // for itr - m_SlotAreas[]
if ( ! HasFound )
{
LOGWARNING ( " %s: Invalid slot area parameter " , __FUNCTION__ ) ;
ASSERT ( ! " Invalid slot area " ) ;
return ;
}
// Broadcast the update packet:
cCSLock Lock ( m_CS ) ;
for ( cPlayerList : : iterator itr = m_OpenedBy . begin ( ) ; itr ! = m_OpenedBy . end ( ) ; + + itr )
{
( * itr ) - > GetClientHandle ( ) - > SendInventorySlot ( m_WindowID , SlotNum , * a_Area - > GetSlot ( a_LocalSlotNum , * * itr ) ) ;
} // for itr - m_OpenedBy[]
}
2012-09-20 09:25:54 -04:00
void cWindow : : SendWholeWindow ( cClientHandle & a_Client )
{
a_Client . SendWholeInventory ( * this ) ;
}
void cWindow : : BroadcastWholeWindow ( void )
{
cCSLock Lock ( m_CS ) ;
for ( cPlayerList : : iterator itr = m_OpenedBy . begin ( ) ; itr ! = m_OpenedBy . end ( ) ; + + itr )
{
SendWholeWindow ( * ( * itr ) - > GetClientHandle ( ) ) ;
} // for itr - m_OpenedBy[]
}
2013-08-18 07:26:37 -04:00
void cWindow : : BroadcastProgress ( int a_Progressbar , int a_Value )
2012-09-20 09:25:54 -04:00
{
cCSLock Lock ( m_CS ) ;
for ( cPlayerList : : iterator itr = m_OpenedBy . begin ( ) ; itr ! = m_OpenedBy . end ( ) ; + + itr )
{
2013-08-18 07:26:37 -04:00
( * itr ) - > GetClientHandle ( ) - > SendWindowProperty ( * this , a_Progressbar , a_Value ) ;
2012-09-20 09:25:54 -04:00
} // for itr - m_OpenedBy[]
}
2013-08-18 07:26:37 -04:00
void cWindow : : SetProperty ( int a_Property , int a_Value )
{
cCSLock Lock ( m_CS ) ;
for ( cPlayerList : : iterator itr = m_OpenedBy . begin ( ) , end = m_OpenedBy . end ( ) ; itr ! = end ; + + itr )
{
( * itr ) - > GetClientHandle ( ) - > SendWindowProperty ( * this , a_Property , a_Value ) ;
} // for itr - m_OpenedBy[]
}
void cWindow : : SetProperty ( int a_Property , int a_Value , cPlayer & a_Player )
{
a_Player . GetClientHandle ( ) - > SendWindowProperty ( * this , a_Property , a_Value ) ;
}
2012-09-20 09:25:54 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cInventoryWindow:
cInventoryWindow : : cInventoryWindow ( cPlayer & a_Player ) :
2013-10-28 08:30:24 -04:00
cWindow ( wtInventory , " Inventory " ) ,
2012-09-20 09:25:54 -04:00
m_Player ( a_Player )
{
m_SlotAreas . push_back ( new cSlotAreaCrafting ( 2 , * this ) ) ; // The creative inventory doesn't display it, but it's still counted into slot numbers
m_SlotAreas . push_back ( new cSlotAreaArmor ( * this ) ) ;
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ) ) ;
2012-09-20 16:10:46 -04:00
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ) ) ;
2012-09-20 09:25:54 -04:00
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCraftingWindow:
cCraftingWindow : : cCraftingWindow ( int a_BlockX , int a_BlockY , int a_BlockZ ) :
2013-10-28 08:30:24 -04:00
cWindow ( wtWorkbench , " Crafting Table " )
2012-09-20 09:25:54 -04:00
{
m_SlotAreas . push_back ( new cSlotAreaCrafting ( 3 , * this ) ) ;
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ) ) ;
2012-09-20 16:10:46 -04:00
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ) ) ;
2012-09-20 09:25:54 -04:00
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChestWindow:
2012-10-20 17:53:09 -04:00
cChestWindow : : cChestWindow ( cChestEntity * a_Chest ) :
2013-10-28 08:30:24 -04:00
cWindow ( wtChest , " Chest " ) ,
2012-09-20 09:25:54 -04:00
m_World ( a_Chest - > GetWorld ( ) ) ,
2012-10-20 17:53:09 -04:00
m_BlockX ( a_Chest - > GetPosX ( ) ) ,
m_BlockY ( a_Chest - > GetPosY ( ) ) ,
m_BlockZ ( a_Chest - > GetPosZ ( ) )
2012-09-20 09:25:54 -04:00
{
m_SlotAreas . push_back ( new cSlotAreaChest ( a_Chest , * this ) ) ;
2012-10-20 17:53:09 -04:00
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ) ) ;
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ) ) ;
2012-09-20 09:25:54 -04:00
2012-10-20 17:53:09 -04:00
// Play the opening sound:
m_World - > BroadcastSoundEffect ( " random.chestopen " , m_BlockX * 8 , m_BlockY * 8 , m_BlockZ * 8 , 1 , 1 ) ;
// Send out the chest-open packet:
m_World - > BroadcastBlockAction ( m_BlockX , m_BlockY , m_BlockZ , 1 , 1 , E_BLOCK_CHEST ) ;
}
cChestWindow : : cChestWindow ( cChestEntity * a_PrimaryChest , cChestEntity * a_SecondaryChest ) :
2013-10-28 08:30:24 -04:00
cWindow ( wtChest , " Double Chest " ) ,
2012-10-20 17:53:09 -04:00
m_World ( a_PrimaryChest - > GetWorld ( ) ) ,
m_BlockX ( a_PrimaryChest - > GetPosX ( ) ) ,
m_BlockY ( a_PrimaryChest - > GetPosY ( ) ) ,
m_BlockZ ( a_PrimaryChest - > GetPosZ ( ) )
{
2013-01-08 00:01:06 -05:00
m_SlotAreas . push_back ( new cSlotAreaDoubleChest ( a_PrimaryChest , a_SecondaryChest , * this ) ) ;
2012-09-20 09:25:54 -04:00
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ) ) ;
2012-09-20 16:10:46 -04:00
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ) ) ;
2012-09-20 09:25:54 -04:00
2013-01-08 00:01:06 -05:00
m_ShouldDistributeToHotbarFirst = false ;
2012-10-20 17:53:09 -04:00
// Play the opening sound:
m_World - > BroadcastSoundEffect ( " random.chestopen " , m_BlockX * 8 , m_BlockY * 8 , m_BlockZ * 8 , 1 , 1 ) ;
2012-09-20 09:25:54 -04:00
// Send out the chest-open packet:
m_World - > BroadcastBlockAction ( m_BlockX , m_BlockY , m_BlockZ , 1 , 1 , E_BLOCK_CHEST ) ;
}
cChestWindow : : ~ cChestWindow ( )
{
// Send out the chest-close packet:
m_World - > BroadcastBlockAction ( m_BlockX , m_BlockY , m_BlockZ , 1 , 0 , E_BLOCK_CHEST ) ;
2012-10-20 17:53:09 -04:00
m_World - > BroadcastSoundEffect ( " random.chestclosed " , m_BlockX * 8 , m_BlockY * 8 , m_BlockZ * 8 , 1 , 1 ) ;
2012-09-20 09:25:54 -04:00
}
2012-12-19 16:19:36 -05:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2013-05-26 10:39:04 -04:00
// cDropSpenserWindow:
2012-12-19 16:19:36 -05:00
2013-05-26 10:39:04 -04:00
cDropSpenserWindow : : cDropSpenserWindow ( int a_BlockX , int a_BlockY , int a_BlockZ , cDropSpenserEntity * a_DropSpenser ) :
2013-10-28 08:30:24 -04:00
cWindow ( wtDropSpenser , " Dropspenser " )
2012-12-19 16:19:36 -05:00
{
2013-06-13 03:36:43 -04:00
m_ShouldDistributeToHotbarFirst = false ;
2013-06-16 16:24:07 -04:00
m_SlotAreas . push_back ( new cSlotAreaItemGrid ( a_DropSpenser - > GetContents ( ) , * this ) ) ;
2012-12-19 16:19:36 -05:00
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ) ) ;
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ) ) ;
}
2013-06-13 03:36:43 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cHopperWindow:
cHopperWindow : : cHopperWindow ( int a_BlockX , int a_BlockY , int a_BlockZ , cHopperEntity * a_Hopper ) :
2013-10-28 08:30:24 -04:00
super ( wtHopper , " Hopper " )
2013-06-13 03:36:43 -04:00
{
m_ShouldDistributeToHotbarFirst = false ;
m_SlotAreas . push_back ( new cSlotAreaItemGrid ( a_Hopper - > GetContents ( ) , * this ) ) ;
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ) ) ;
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ) ) ;
}
2012-09-20 09:25:54 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFurnaceWindow:
cFurnaceWindow : : cFurnaceWindow ( int a_BlockX , int a_BlockY , int a_BlockZ , cFurnaceEntity * a_Furnace ) :
2013-10-28 08:30:24 -04:00
cWindow ( wtFurnace , " Furnace " )
2012-09-20 09:25:54 -04:00
{
2013-06-13 03:36:43 -04:00
m_ShouldDistributeToHotbarFirst = false ;
2012-09-20 09:25:54 -04:00
m_SlotAreas . push_back ( new cSlotAreaFurnace ( a_Furnace , * this ) ) ;
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ) ) ;
2012-09-20 16:10:46 -04:00
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ) ) ;
2012-09-20 09:25:54 -04:00
}