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"
2014-07-30 15:59:35 -04:00
# include "../BlockEntities/BeaconEntity.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-12-06 19:18:58 -05:00
# include "../BlockEntities/EnderChestEntity.h"
2013-06-13 03:36:43 -04:00
# include "../BlockEntities/HopperEntity.h"
2014-09-12 18:18:02 -04:00
# include "../Entities/Minecart.h"
2014-01-23 02:27:39 -05:00
# include "../Root.h"
# include "../Bindings/PluginManager.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_IsDestroyed ( false ) ,
2014-10-20 16:55:07 -04:00
m_Owner ( nullptr )
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
}
2014-09-11 17:17:27 -04:00
const AString cWindow : : GetWindowTypeName ( void ) const
{
switch ( m_WindowType )
{
case wtChest : return " minecraft:chest " ;
case wtWorkbench : return " minecraft:crafting_table " ;
case wtFurnace : return " minecraft:furnace " ;
case wtDropSpenser : return " minecraft:dispenser " ;
case wtEnchantment : return " minecraft:enchanting_table " ;
case wtBrewery : return " minecraft:brewing_stand " ;
case wtNPCTrade : return " minecraft:villager " ;
case wtBeacon : return " minecraft:beacon " ;
case wtAnvil : return " minecraft:anvil " ;
case wtHopper : return " minecraft:hopper " ;
case wtDropper : return " minecraft:dropper " ;
case wtAnimalChest : return " EntityHorse " ;
default :
{
ASSERT ( ! " Unknown inventory type! " ) ;
return " " ;
}
}
}
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 ) ;
2014-10-20 16:55:07 -04:00
if ( Area = = nullptr )
2013-05-30 04:40:13 -04:00
{
2014-10-20 16:55:07 -04:00
LOGWARNING ( " %s: requesting item from an invalid SlotArea (SlotNum %d), returning nullptr. " , __FUNCTION__ , a_SlotNum ) ;
return nullptr ;
2013-05-30 04:40:13 -04:00
}
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 ) ;
2014-10-20 16:55:07 -04:00
if ( Area = = nullptr )
2013-05-30 04:40:13 -04:00
{
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 ) ;
2014-10-20 16:55:07 -04:00
if ( Item = = nullptr )
2012-09-20 09:25:54 -04:00
{
a_Slots . push_back ( cItem ( ) ) ;
}
else
{
a_Slots . push_back ( * Item ) ;
}
}
} // for itr - m_SlotAreas[]
}
void cWindow : : Clicked (
2014-07-17 16:50:58 -04:00
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
)
{
2014-07-01 08:47:49 -04:00
cPluginManager * PlgMgr = cRoot : : Get ( ) - > GetPluginManager ( ) ;
2012-09-20 09:25:54 -04:00
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
{
2014-07-05 18:40:59 -04:00
case caLeftClickOutside :
2013-05-08 05:45:07 -04:00
case caRightClickOutside :
2012-09-20 09:25:54 -04:00
{
2014-01-23 22:11:10 -05:00
if ( PlgMgr - > CallHookPlayerTossingItem ( a_Player ) )
{
// A plugin doesn't agree with the tossing. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
return ;
}
if ( a_Player . IsGameModeCreative ( ) )
2014-01-23 02:27:39 -05:00
{
2014-01-23 22:11:10 -05:00
a_Player . TossPickup ( a_ClickedItem ) ;
2014-01-23 02:27:39 -05:00
}
2014-07-05 18:40:59 -04:00
if ( a_ClickAction = = caLeftClickOutside )
2014-01-23 02:27:39 -05:00
{
2014-07-05 18:40:59 -04:00
// Toss all dragged items:
a_Player . TossHeldItem ( a_Player . GetDraggingItem ( ) . m_ItemCount ) ;
2014-01-23 02:27:39 -05:00
}
2014-07-05 18:40:59 -04:00
else
2014-01-23 22:11:10 -05:00
{
2014-07-05 18:40:59 -04:00
// Toss one of the dragged items:
a_Player . TossHeldItem ( ) ;
2014-01-23 22:11:10 -05:00
}
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-12-07 18:42:43 -05:00
default :
{
break ;
}
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[]
}
2013-11-08 15:32:14 -05:00
a_Player . GetClientHandle ( ) - > SendWindowOpen ( * this ) ;
2012-09-20 09:25:54 -04:00
}
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
2014-06-04 13:59:56 -04:00
if ( ! a_Player . GetDraggingItem ( ) . IsEmpty ( ) )
2012-09-20 09:25:54 -04:00
{
LOGD ( " Player holds item! Dropping it... " ) ;
2014-01-23 22:11:10 -05:00
a_Player . TossHeldItem ( a_Player . GetDraggingItem ( ) . m_ItemCount ) ;
2012-09-20 09:25:54 -04:00
}
cClientHandle * ClientHandle = a_Player . GetClientHandle ( ) ;
2014-10-20 16:55:07 -04:00
if ( ClientHandle ! = nullptr )
2012-09-20 09:25:54 -04:00
{
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 ( )
{
2014-10-20 16:55:07 -04:00
m_Owner = nullptr ;
2012-09-20 09:25:54 -04:00
// Close window for each player. Note that the last one needs special handling
while ( m_OpenedBy . size ( ) > 1 )
{
2014-07-21 09:19:48 -04:00
( * m_OpenedBy . begin ( ) ) - > CloseWindow ( ) ;
2012-09-20 09:25:54 -04:00
}
2014-07-21 09:19:48 -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 ;
}
2014-12-17 13:14:01 -05:00
void cWindow : : DistributeStackToAreas ( cItem & a_ItemStack , cPlayer & a_Player , cSlotAreas & a_AreasInOrder , bool a_ShouldApply , bool a_BackFill )
2014-12-13 12:49:11 -05:00
{
for ( size_t i = 0 ; i < 2 ; i + + )
{
2014-12-17 13:14:01 -05:00
for ( auto SlotArea : a_AreasInOrder )
2012-09-20 16:10:46 -04:00
{
2014-12-17 13:14:01 -05:00
SlotArea - > DistributeStack ( a_ItemStack , a_Player , a_ShouldApply , ( i = = 0 ) , a_BackFill ) ;
2012-09-20 16:10:46 -04:00
if ( a_ItemStack . IsEmpty ( ) )
{
// Distributed it all
return ;
}
2014-12-13 12:49:11 -05:00
}
}
2012-09-20 16:10:46 -04:00
}
2013-11-10 12:42:46 -05:00
bool cWindow : : CollectItemsToHand ( cItem & a_Dragging , cSlotArea & a_Area , cPlayer & a_Player , bool a_CollectFullStacks )
{
// First ask the slot areas from a_Area till the end of list:
bool ShouldCollect = false ;
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
if ( & a_Area = = * itr )
{
ShouldCollect = true ;
}
if ( ! ShouldCollect )
{
continue ;
}
if ( ( * itr ) - > CollectItemsToHand ( a_Dragging , a_Player , a_CollectFullStacks ) )
{
// a_Dragging is full
return true ;
}
}
// a_Dragging still not full, ask slot areas before a_Area in the list:
for ( cSlotAreas : : iterator itr = m_SlotAreas . begin ( ) , end = m_SlotAreas . end ( ) ; itr ! = end ; + + itr )
{
if ( * itr = = & a_Area )
{
// All areas processed
return false ;
}
if ( ( * itr ) - > CollectItemsToHand ( a_Dragging , a_Player , a_CollectFullStacks ) )
{
// a_Dragging is full
return true ;
}
}
// Shouldn't reach here
// a_Area is expected to be part of m_SlotAreas[], so the "return false" in the loop above should have returned already
ASSERT ( ! " This branch should not be reached " ) ;
return false ;
}
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
{
2014-10-20 16:55:07 -04:00
if ( m_Owner ! = nullptr )
2012-09-20 09:25:54 -04:00
{
m_Owner - > CloseWindow ( ) ;
2014-10-20 16:55:07 -04:00
m_Owner = nullptr ;
2012-09-20 09:25:54 -04:00
}
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 " ) ;
2014-10-20 16:55:07 -04:00
return nullptr ;
2013-05-30 04:40:13 -04:00
}
// 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 " ) ;
2014-10-20 16:55:07 -04:00
return nullptr ;
2013-05-30 04:40:13 -04:00
}
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 " ) ;
2014-10-20 16:55:07 -04:00
return nullptr ;
2013-05-30 04:40:13 -04:00
}
// 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 " ) ;
2014-10-20 16:55:07 -04:00
return nullptr ;
2013-05-30 04:40:13 -04:00
}
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 ( ) ) ;
2014-05-08 14:16:35 -04:00
int ToEachSlot = ( int ) ToDistribute . m_ItemCount / ( int ) SlotNums . size ( ) ;
2013-05-30 06:10:58 -04:00
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
{
2014-03-12 13:34:50 -04:00
LOGWARNING ( " %s: Distributing less items (%d) than slots ( " SIZE_T_FMT " ) " , __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 ) ;
2014-10-20 16:55:07 -04:00
if ( Area = = nullptr )
2013-05-30 04:40:13 -04:00
{
LOGWARNING ( " %s: Bad SlotArea for slot %d " , __FUNCTION__ , * itr ) ;
continue ;
}
// Modify the item at the slot
cItem AtSlot ( * Area - > GetSlot ( LocalSlotNum , a_Player ) ) ;
2013-11-12 07:15:09 -05:00
int MaxStack = AtSlot . GetMaxStackSize ( ) ;
2013-05-30 04:40:13 -04:00
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 ;
}
2014-01-16 14:00:49 -05:00
else if ( AtSlot . IsEqual ( a_Item ) )
2013-05-30 04:40:13 -04:00
{
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[]
}
2014-10-03 16:32:41 -04:00
void cWindow : : SetProperty ( short a_Property , short a_Value )
2013-08-18 07:26:37 -04:00
{
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[]
}
2014-10-03 16:32:41 -04:00
void cWindow : : SetProperty ( short a_Property , short a_Value , cPlayer & a_Player )
2013-08-18 07:26:37 -04:00
{
a_Player . GetClientHandle ( ) - > SendWindowProperty ( * this , a_Property , a_Value ) ;
}