2012-09-20 13:25:54 +00:00
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 17:19:34 +00:00
#include "Window.h"
2013-05-28 19:12:47 +00:00
#include "WindowOwner.h"
#include "SlotArea.h"
2012-09-23 22:09:57 +00:00
#include "../Item.h"
#include "../ClientHandle.h"
2013-08-19 11:39:13 +02:00
#include "../Entities/Player.h"
#include "../Entities/Pickup.h"
2012-09-23 22:09:57 +00:00
#include "../Inventory.h"
2012-09-29 13:59:32 +00:00
#include "../Items/ItemHandler.h"
2013-05-28 19:12:47 +00:00
#include "../BlockEntities/ChestEntity.h"
2013-06-16 20:24:07 +00:00
#include "../BlockEntities/DropSpenserEntity.h"
2013-06-13 07:36:43 +00:00
#include "../BlockEntities/HopperEntity.h"
2012-09-20 13:25:54 +00:00
char cWindow :: m_WindowIDCounter = 1 ;
2013-05-30 08:40:13 +00:00
cWindow :: cWindow ( cWindow :: WindowType a_WindowType , const AString & a_WindowTitle ) :
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 13:25:54 +00:00
{
if ( a_WindowType == Inventory )
{
m_WindowID = 0 ;
}
}
cWindow ::~ cWindow ()
{
2012-09-29 19:55:18 +00:00
for ( cSlotAreas :: iterator itr = m_SlotAreas . begin (), end = m_SlotAreas . end (); itr != end ; ++ itr )
{
delete * itr ;
}
m_SlotAreas . clear ();
2012-09-20 13:25:54 +00: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 08:40:13 +00: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 19:34:09 +00: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 13:25:54 +00: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 09:45:07 +00:00
int a_WindowID , short a_SlotNum , eClickAction a_ClickAction ,
2012-09-20 13:25:54 +00:00
const cItem & a_ClickedItem
)
{
if ( a_WindowID != m_WindowID )
{
2013-05-30 08:40:13 +00: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 13:25:54 +00:00
return ;
}
2013-05-08 09:45:07 +00:00
switch ( a_ClickAction )
2012-09-20 13:25:54 +00:00
{
2013-05-08 09:45:07 +00:00
case caRightClickOutside :
2012-09-20 13:25:54 +00:00
{
2013-05-08 09:45:07 +00:00
// Toss one of the dragged items:
2012-09-20 13:25:54 +00:00
a_Player . TossItem ( true );
2013-05-08 09:45:07 +00:00
return ;
2012-09-20 13:25:54 +00:00
}
2013-05-08 09:45:07 +00:00
case caLeftClickOutside :
2012-09-20 13:25:54 +00:00
{
2013-05-08 09:45:07 +00:00
// Toss all dragged items:
2012-09-20 13:25:54 +00:00
a_Player . TossItem ( true , a_Player . GetDraggingItem (). m_ItemCount );
2013-05-08 09:45:07 +00:00
return ;
}
case caLeftClickOutsideHoldNothing :
case caRightClickOutsideHoldNothing :
{
// Nothing needed
return ;
2012-09-20 13:25:54 +00:00
}
2013-05-30 08:40:13 +00: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 09:45:07 +00:00
}
if ( a_SlotNum < 0 )
{
// TODO: Other click actions with irrelevant slot number (FS #371)
2012-09-20 13:25:54 +00: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 09:45:07 +00:00
( * itr ) -> Clicked ( a_Player , LocalSlotNum , a_ClickAction , a_ClickedItem );
2012-09-20 13:25:54 +00: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 21:59:25 +00:00
bool cWindow :: ClosedByPlayer ( cPlayer & a_Player , bool a_CanRefuse )
2012-09-20 13:25:54 +00: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 11:47:31 +00:00
ClientHandle -> SendWindowClose ( * this );
2012-09-20 13:25:54 +00: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 11:47:31 +00:00
if (( m_WindowType != Inventory ) && m_OpenedBy . empty ())
2012-09-20 13:25:54 +00:00
{
Destroy ();
}
}
if ( m_IsDestroyed )
{
delete this ;
}
2013-05-30 20:40:43 +00:00
return true ;
2012-09-20 13:25:54 +00: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 19:34:09 +00:00
( * m_OpenedBy . begin () ) -> CloseWindow ();
2012-09-20 13:25:54 +00:00
}
2013-05-30 19:34:09 +00:00
( * m_OpenedBy . begin () ) -> CloseWindow ();
2012-09-20 13:25:54 +00: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 20:10:46 +00: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 05:01:06 +00:00
if ( m_ShouldDistributeToHotbarFirst )
2012-09-20 20:10:46 +00:00
{
2013-01-08 05:01:06 +00:00
// First distribute into the hotbar:
if ( a_ExcludeArea != m_SlotAreas . back ())
2012-09-20 20:10:46 +00:00
{
2013-01-08 05:01:06 +00:00
m_SlotAreas . back () -> DistributeStack ( a_ItemStack , a_Player , a_ShouldApply , ( Pass == 0 ));
if ( a_ItemStack . IsEmpty ())
{
// Distributed it all
return ;
}
2012-09-20 20:10:46 +00:00
}
}
2013-01-08 05:01:06 +00:00
2012-09-20 20:10:46 +00:00
// The distribute to all other areas:
2013-01-08 05:01:06 +00: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 20:10:46 +00: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 20:50:34 +00: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 20:10:46 +00:00
void cWindow :: Destroy ( void )
2012-09-20 13:25:54 +00:00
{
if ( m_Owner != NULL )
{
m_Owner -> CloseWindow ();
m_Owner = NULL ;
}
m_IsDestroyed = true ;
}
2013-05-30 08:40:13 +00: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 10:10:58 +00: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 08:40:13 +00:00
2013-05-30 10:10:58 +00: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 08:40:13 +00:00
{
2013-05-30 10:10:58 +00:00
LOGWARNING ( "%s: Distributing less items (%d) than slots (%u)" , __FUNCTION__ , ( int ) a_Item . m_ItemCount , a_SlotNums . size ());
2013-05-30 08:40:13 +00: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 10:10:58 +00:00
return 0 ;
2013-05-30 08:40:13 +00:00
}
// Distribute to individual slots, keep track of how many items were actually distributed (full stacks etc.)
int NumDistributed = 0 ;
2013-05-30 10:10:58 +00:00
for ( cSlotNums :: const_iterator itr = a_SlotNums . begin (), end = a_SlotNums . end (); itr != end ; ++ itr )
2013-05-30 08:40:13 +00: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 10:10:58 +00:00
cItem ToStore ( a_Item );
ToStore . m_ItemCount = std :: min ( a_NumToEachSlot , ( int ) MaxStack );
2013-05-30 08:40:13 +00:00
Area -> SetSlot ( LocalSlotNum , a_Player , ToStore );
NumDistributed += ToStore . m_ItemCount ;
}
else
{
2013-05-30 10:10:58 +00:00
// Occupied, add and cap at MaxStack:
int CanStore = std :: min ( a_NumToEachSlot , ( int ) MaxStack - AtSlot . m_ItemCount );
2013-05-30 08:40:13 +00:00
AtSlot . m_ItemCount += CanStore ;
Area -> SetSlot ( LocalSlotNum , a_Player , AtSlot );
NumDistributed += CanStore ;
}
} // for itr - SlotNums[]
2013-05-30 10:10:58 +00:00
return NumDistributed ;
2013-05-30 08:40:13 +00:00
}
2013-06-13 07:36:43 +00: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 13:25:54 +00: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 13:26:37 +02:00
void cWindow :: BroadcastProgress ( int a_Progressbar , int a_Value )
2012-09-20 13:25:54 +00:00
{
cCSLock Lock ( m_CS );
for ( cPlayerList :: iterator itr = m_OpenedBy . begin (); itr != m_OpenedBy . end (); ++ itr )
{
2013-08-18 13:26:37 +02:00
( * itr ) -> GetClientHandle () -> SendWindowProperty ( * this , a_Progressbar , a_Value );
2012-09-20 13:25:54 +00:00
} // for itr - m_OpenedBy[]
}
2013-08-18 13:26:37 +02: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 13:25:54 +00:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cInventoryWindow:
cInventoryWindow :: cInventoryWindow ( cPlayer & a_Player ) :
2013-07-27 22:32:07 +01:00
cWindow ( cWindow :: Inventory , "Inventory" ),
2012-09-20 13:25:54 +00: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 20:10:46 +00:00
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ));
2012-09-20 13:25:54 +00:00
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cCraftingWindow:
cCraftingWindow :: cCraftingWindow ( int a_BlockX , int a_BlockY , int a_BlockZ ) :
2013-07-27 22:32:07 +01:00
cWindow ( cWindow :: Workbench , "Crafting Table" )
2012-09-20 13:25:54 +00:00
{
m_SlotAreas . push_back ( new cSlotAreaCrafting ( 3 , * this ));
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ));
2012-09-20 20:10:46 +00:00
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ));
2012-09-20 13:25:54 +00:00
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChestWindow:
2012-10-20 21:53:09 +00:00
cChestWindow :: cChestWindow ( cChestEntity * a_Chest ) :
2013-07-27 22:32:07 +01:00
cWindow ( cWindow :: Chest , "Chest" ),
2012-09-20 13:25:54 +00:00
m_World ( a_Chest -> GetWorld ()),
2012-10-20 21:53:09 +00:00
m_BlockX ( a_Chest -> GetPosX ()),
m_BlockY ( a_Chest -> GetPosY ()),
m_BlockZ ( a_Chest -> GetPosZ ())
2012-09-20 13:25:54 +00:00
{
m_SlotAreas . push_back ( new cSlotAreaChest ( a_Chest , * this ));
2012-10-20 21:53:09 +00:00
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ));
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ));
2012-09-20 13:25:54 +00:00
2012-10-20 21:53:09 +00: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-07-27 22:32:07 +01:00
cWindow ( cWindow :: Chest , "Double Chest" ),
2012-10-20 21:53:09 +00:00
m_World ( a_PrimaryChest -> GetWorld ()),
m_BlockX ( a_PrimaryChest -> GetPosX ()),
m_BlockY ( a_PrimaryChest -> GetPosY ()),
m_BlockZ ( a_PrimaryChest -> GetPosZ ())
{
2013-01-08 05:01:06 +00:00
m_SlotAreas . push_back ( new cSlotAreaDoubleChest ( a_PrimaryChest , a_SecondaryChest , * this ));
2012-09-20 13:25:54 +00:00
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ));
2012-09-20 20:10:46 +00:00
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ));
2012-09-20 13:25:54 +00:00
2013-01-08 05:01:06 +00:00
m_ShouldDistributeToHotbarFirst = false ;
2012-10-20 21:53:09 +00:00
// Play the opening sound:
m_World -> BroadcastSoundEffect ( "random.chestopen" , m_BlockX * 8 , m_BlockY * 8 , m_BlockZ * 8 , 1 , 1 );
2012-09-20 13:25:54 +00: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 21:53:09 +00:00
m_World -> BroadcastSoundEffect ( "random.chestclosed" , m_BlockX * 8 , m_BlockY * 8 , m_BlockZ * 8 , 1 , 1 );
2012-09-20 13:25:54 +00:00
}
2012-12-19 21:19:36 +00:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2013-05-26 14:39:04 +00:00
// cDropSpenserWindow:
2012-12-19 21:19:36 +00:00
2013-05-26 14:39:04 +00:00
cDropSpenserWindow :: cDropSpenserWindow ( int a_BlockX , int a_BlockY , int a_BlockZ , cDropSpenserEntity * a_DropSpenser ) :
2013-07-27 22:32:07 +01:00
cWindow ( cWindow :: DropSpenser , "Dropspenser" )
2012-12-19 21:19:36 +00:00
{
2013-06-13 07:36:43 +00:00
m_ShouldDistributeToHotbarFirst = false ;
2013-06-16 20:24:07 +00:00
m_SlotAreas . push_back ( new cSlotAreaItemGrid ( a_DropSpenser -> GetContents (), * this ));
2012-12-19 21:19:36 +00:00
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ));
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ));
}
2013-06-13 07:36:43 +00:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cHopperWindow:
cHopperWindow :: cHopperWindow ( int a_BlockX , int a_BlockY , int a_BlockZ , cHopperEntity * a_Hopper ) :
2013-07-27 22:32:07 +01:00
super ( cWindow :: Hopper , "Hopper" )
2013-06-13 07:36:43 +00: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 13:25:54 +00:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFurnaceWindow:
cFurnaceWindow :: cFurnaceWindow ( int a_BlockX , int a_BlockY , int a_BlockZ , cFurnaceEntity * a_Furnace ) :
2013-07-27 22:32:07 +01:00
cWindow ( cWindow :: Furnace , "Furnace" )
2012-09-20 13:25:54 +00:00
{
2013-06-13 07:36:43 +00:00
m_ShouldDistributeToHotbarFirst = false ;
2012-09-20 13:25:54 +00:00
m_SlotAreas . push_back ( new cSlotAreaFurnace ( a_Furnace , * this ));
m_SlotAreas . push_back ( new cSlotAreaInventory ( * this ));
2012-09-20 20:10:46 +00:00
m_SlotAreas . push_back ( new cSlotAreaHotBar ( * this ));
2012-09-20 13:25:54 +00:00
}