2012-06-14 13:06:06 +00:00
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 22:09:57 +00:00
#include "Inventory.h"
2013-08-19 11:39:13 +02:00
#include "Entities/Player.h"
2012-09-23 22:09:57 +00:00
#include "ClientHandle.h"
2012-09-23 17:19:34 +00:00
#include "UI/Window.h"
2012-09-23 22:09:57 +00:00
#include "Item.h"
#include "Root.h"
2013-05-19 18:22:37 +00:00
#include "World.h"
2012-06-14 13:06:06 +00:00
2013-11-27 09:17:25 +01:00
#include "json/json.h"
2012-06-14 13:06:06 +00:00
2012-09-29 13:59:32 +00:00
#include "Items/ItemHandler.h"
2012-08-11 19:54:57 +00:00
2012-06-14 13:06:06 +00:00
2013-05-19 18:22:37 +00:00
cInventory :: cInventory ( cPlayer & a_Owner ) :
2013-05-24 07:30:39 +00:00
m_ArmorSlots ( 1 , 4 ), // 1 x 4 slots
m_InventorySlots ( 9 , 3 ), // 9 x 3 slots
m_HotbarSlots ( 9 , 1 ), // 9 x 1 slots
2017-05-24 08:09:58 +02:00
m_ShieldSlots ( 1 , 1 ), // 1 x 1 slots
2013-05-19 18:22:37 +00:00
m_Owner ( a_Owner )
{
2013-05-24 07:30:39 +00:00
// Ask each ItemGrid to report changes to us:
m_ArmorSlots . AddListener ( * this );
m_InventorySlots . AddListener ( * this );
m_HotbarSlots . AddListener ( * this );
2017-12-21 11:55:23 +00:00
m_ShieldSlots . AddListener ( * this );
2016-02-05 23:45:45 +02:00
2013-05-19 18:22:37 +00:00
SetEquippedSlotNum ( 0 );
}
2013-05-24 07:30:39 +00:00
void cInventory :: Clear ( void )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
m_ArmorSlots . Clear ();
m_InventorySlots . Clear ();
m_HotbarSlots . Clear ();
2017-05-24 08:09:58 +02:00
m_ShieldSlots . Clear ();
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
int cInventory :: HowManyCanFit ( const cItem & a_ItemStack , bool a_ConsiderEmptySlots )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
return HowManyCanFit ( a_ItemStack , 0 , invNumSlots - 1 , a_ConsiderEmptySlots );
}
2012-06-14 13:06:06 +00:00
2013-05-24 07:30:39 +00:00
int cInventory :: HowManyCanFit ( const cItem & a_ItemStack , int a_BeginSlotNum , int a_EndSlotNum , bool a_ConsiderEmptySlots )
{
2013-12-22 14:28:47 +00:00
UNUSED ( a_ConsiderEmptySlots );
2013-05-24 07:30:39 +00:00
if (( a_BeginSlotNum < 0 ) || ( a_BeginSlotNum >= invNumSlots ))
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
LOGWARNING ( "%s: Bad BeginSlotNum, got %d, there are %d slots; correcting to 0." , __FUNCTION__ , a_BeginSlotNum , invNumSlots - 1 );
a_BeginSlotNum = 0 ;
}
if (( a_EndSlotNum < 0 ) || ( a_EndSlotNum >= invNumSlots ))
{
LOGWARNING ( "%s: Bad EndSlotNum, got %d, there are %d slots; correcting to %d." , __FUNCTION__ , a_BeginSlotNum , invNumSlots , invNumSlots - 1 );
a_EndSlotNum = invNumSlots - 1 ;
}
if ( a_BeginSlotNum > a_EndSlotNum )
{
std :: swap ( a_BeginSlotNum , a_EndSlotNum );
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
char NumLeft = a_ItemStack . m_ItemCount ;
int MaxStack = ItemHandler ( a_ItemStack . m_ItemType ) -> GetMaxStackSize ();
for ( int i = a_BeginSlotNum ; i <= a_EndSlotNum ; i ++ )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
const cItem & Slot = GetSlot ( i );
if ( Slot . IsEmpty ())
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
NumLeft -= MaxStack ;
2012-06-14 13:06:06 +00:00
}
2014-01-16 19:00:49 +00:00
else if ( Slot . IsEqual ( a_ItemStack ))
2013-05-24 07:30:39 +00:00
{
NumLeft -= MaxStack - Slot . m_ItemCount ;
}
if ( NumLeft <= 0 )
{
// All items fit
return a_ItemStack . m_ItemCount ;
}
} // for i - m_Slots[]
return a_ItemStack . m_ItemCount - NumLeft ;
2012-06-14 13:06:06 +00:00
}
2018-07-26 22:24:36 +01:00
2015-05-18 14:30:16 +01:00
int cInventory :: AddItem ( const cItem & a_Item , bool a_AllowNewStacks )
2012-10-24 12:48:25 +00:00
{
2013-05-24 07:30:39 +00:00
cItem ToAdd ( a_Item );
int res = 0 ;
2012-10-24 12:48:25 +00:00
2014-07-20 01:22:58 +02:00
// When the item is a armor, try to set it directly to the armor slot.
if ( ItemCategory :: IsArmor ( a_Item . m_ItemType ))
{
2014-08-25 18:25:39 +03:00
for ( int i = 0 ; i < m_ArmorSlots . GetNumSlots (); i ++ )
2014-07-20 01:22:58 +02:00
{
if ( m_ArmorSlots . GetSlot ( i ). IsEmpty () && cSlotAreaArmor :: CanPlaceArmorInSlot ( i , a_Item ))
{
m_ArmorSlots . SetSlot ( i , a_Item );
return a_Item . m_ItemCount ;
}
}
}
2015-05-18 14:30:16 +01:00
for ( int SlotIdx = 0 ; SlotIdx < m_InventorySlots . GetNumSlots (); ++ SlotIdx )
{
auto & Slot = m_InventorySlots . GetSlot ( SlotIdx );
if ( Slot . IsEqual ( a_Item ))
{
cItemHandler Handler ( Slot . m_ItemType );
int AmountToAdd = std :: min ( static_cast < char > ( Handler . GetMaxStackSize () - Slot . m_ItemCount ), ToAdd . m_ItemCount );
res += AmountToAdd ;
cItem SlotAdjusted ( Slot );
SlotAdjusted . m_ItemCount += AmountToAdd ;
m_InventorySlots . SetSlot ( SlotIdx , SlotAdjusted );
ToAdd . m_ItemCount -= AmountToAdd ;
if ( ToAdd . m_ItemCount == 0 )
{
return res ;
}
}
}
res += m_HotbarSlots . AddItem ( ToAdd , a_AllowNewStacks );
2015-07-29 09:04:03 -06:00
ToAdd . m_ItemCount = static_cast < char > ( a_Item . m_ItemCount - res );
2013-05-24 07:30:39 +00:00
if ( ToAdd . m_ItemCount == 0 )
{
return res ;
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
res += m_InventorySlots . AddItem ( ToAdd , a_AllowNewStacks );
return res ;
2012-10-24 12:48:25 +00:00
}
2015-05-18 14:30:16 +01:00
int cInventory :: AddItems ( cItems & a_ItemStackList , bool a_AllowNewStacks )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
int TotalAdded = 0 ;
for ( cItems :: iterator itr = a_ItemStackList . begin (); itr != a_ItemStackList . end ();)
2012-06-14 13:06:06 +00:00
{
2015-05-18 14:30:16 +01:00
int NumAdded = AddItem ( * itr , a_AllowNewStacks );
2013-05-24 07:30:39 +00:00
if ( itr -> m_ItemCount == NumAdded )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
itr = a_ItemStackList . erase ( itr );
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
else
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
itr -> m_ItemCount -= NumAdded ;
++ itr ;
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
TotalAdded += NumAdded ;
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
return TotalAdded ;
2012-06-14 13:06:06 +00:00
}
2014-07-18 23:11:59 +02:00
int cInventory :: RemoveItem ( const cItem & a_ItemStack )
{
2017-05-24 08:09:58 +02:00
int RemovedItems = m_ShieldSlots . RemoveItem ( a_ItemStack );
if ( RemovedItems < a_ItemStack . m_ItemCount )
{
RemovedItems += m_HotbarSlots . RemoveItem ( a_ItemStack );
}
2014-07-18 23:11:59 +02:00
if ( RemovedItems < a_ItemStack . m_ItemCount )
{
cItem Temp ( a_ItemStack );
Temp . m_ItemCount -= RemovedItems ;
RemovedItems += m_InventorySlots . RemoveItem ( Temp );
}
return RemovedItems ;
}
2013-05-24 07:30:39 +00:00
bool cInventory :: RemoveOneEquippedItem ( void )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
if ( m_HotbarSlots . GetSlot ( m_EquippedSlotNum ). IsEmpty ())
2013-05-19 18:22:37 +00:00
{
2013-05-24 07:30:39 +00:00
return false ;
2013-05-19 18:22:37 +00:00
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
m_HotbarSlots . ChangeSlotCount ( m_EquippedSlotNum , - 1 );
return true ;
}
int cInventory :: HowManyItems ( const cItem & a_Item )
{
return
m_ArmorSlots . HowManyItems ( a_Item ) +
m_InventorySlots . HowManyItems ( a_Item ) +
2017-05-24 08:09:58 +02:00
m_HotbarSlots . HowManyItems ( a_Item ) +
m_ShieldSlots . HowManyItems ( a_Item );
2013-05-24 07:30:39 +00:00
}
bool cInventory :: HasItems ( const cItem & a_ItemStack )
{
int CurrentlyHave = HowManyItems ( a_ItemStack );
return ( CurrentlyHave >= a_ItemStack . m_ItemCount );
2012-06-14 13:06:06 +00:00
}
2013-05-19 18:22:37 +00:00
void cInventory :: SetSlot ( int a_SlotNum , const cItem & a_Item )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
if (( a_SlotNum < 0 ) || ( a_SlotNum >= invNumSlots ))
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
LOGWARNING ( "%s: requesting an invalid slot index: %d out of %d. Ignoring." , __FUNCTION__ , a_SlotNum , invNumSlots - 1 );
2013-05-19 18:22:37 +00:00
return ;
}
2013-05-24 07:30:39 +00:00
int GridSlotNum = 0 ;
cItemGrid * Grid = GetGridForSlotNum ( a_SlotNum , GridSlotNum );
2014-10-20 21:55:07 +01:00
if ( Grid == nullptr )
2013-05-19 18:22:37 +00:00
{
2013-05-24 07:30:39 +00:00
LOGWARNING ( "%s(%d): requesting an invalid itemgrid. Ignoring." , __FUNCTION__ , a_SlotNum );
return ;
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
Grid -> SetSlot ( GridSlotNum , a_Item );
}
void cInventory :: SetArmorSlot ( int a_ArmorSlotNum , const cItem & a_Item )
{
m_ArmorSlots . SetSlot ( a_ArmorSlotNum , a_Item );
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
void cInventory :: SetInventorySlot ( int a_InventorySlotNum , const cItem & a_Item )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
m_InventorySlots . SetSlot ( a_InventorySlotNum , a_Item );
}
void cInventory :: SetHotbarSlot ( int a_HotBarSlotNum , const cItem & a_Item )
{
m_HotbarSlots . SetSlot ( a_HotBarSlotNum , a_Item );
2012-06-14 13:06:06 +00:00
}
2017-05-24 08:09:58 +02:00
void cInventory :: SetShieldSlot ( const cItem & a_Item )
{
m_ShieldSlots . SetSlot ( 0 , a_Item );
}
2014-05-09 23:10:02 +02:00
void cInventory :: SendEquippedSlot ()
{
int EquippedSlotNum = cInventory :: invArmorCount + cInventory :: invInventoryCount + GetEquippedSlotNum ();
SendSlot ( EquippedSlotNum );
}
2013-05-19 18:22:37 +00:00
const cItem & cInventory :: GetSlot ( int a_SlotNum ) const
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
if (( a_SlotNum < 0 ) || ( a_SlotNum >= invNumSlots ))
2013-05-19 18:22:37 +00:00
{
2013-05-24 07:30:39 +00:00
LOGWARNING ( "%s: requesting an invalid slot index: %d out of %d. Returning the first inventory slot instead." , __FUNCTION__ , a_SlotNum , invNumSlots - 1 );
return m_InventorySlots . GetSlot ( 0 );
2013-05-19 18:22:37 +00:00
}
2013-05-24 07:30:39 +00:00
int GridSlotNum = 0 ;
const cItemGrid * Grid = GetGridForSlotNum ( a_SlotNum , GridSlotNum );
2014-10-20 21:55:07 +01:00
if ( Grid == nullptr )
2013-05-24 07:30:39 +00:00
{
// Something went wrong, but we don't know what. We must return a value, so return the first inventory slot
LOGWARNING ( "%s(%d): requesting an invalid ItemGrid, returning the first inventory slot instead." , __FUNCTION__ , a_SlotNum );
return m_InventorySlots . GetSlot ( 0 );
}
return Grid -> GetSlot ( GridSlotNum );
}
const cItem & cInventory :: GetArmorSlot ( int a_ArmorSlotNum ) const
{
if (( a_ArmorSlotNum < 0 ) || ( a_ArmorSlotNum >= invArmorCount ))
{
LOGWARNING ( "%s: requesting an invalid slot index: %d out of %d. Returning the first one instead" , __FUNCTION__ , a_ArmorSlotNum , invArmorCount - 1 );
return m_ArmorSlots . GetSlot ( 0 );
}
return m_ArmorSlots . GetSlot ( a_ArmorSlotNum );
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
const cItem & cInventory :: GetInventorySlot ( int a_InventorySlotNum ) const
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
if (( a_InventorySlotNum < 0 ) || ( a_InventorySlotNum >= invInventoryCount ))
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
LOGWARNING ( "%s: requesting an invalid slot index: %d out of %d. Returning the first one instead" , __FUNCTION__ , a_InventorySlotNum , invInventoryCount - 1 );
return m_InventorySlots . GetSlot ( 0 );
2012-06-14 13:06:06 +00:00
}
2013-05-24 07:30:39 +00:00
return m_InventorySlots . GetSlot ( a_InventorySlotNum );
}
const cItem & cInventory :: GetHotbarSlot ( int a_SlotNum ) const
{
if (( a_SlotNum < 0 ) || ( a_SlotNum >= invHotbarCount ))
{
LOGWARNING ( "%s: requesting an invalid slot index: %d out of %d. Returning the first one instead" , __FUNCTION__ , a_SlotNum , invHotbarCount - 1 );
return m_HotbarSlots . GetSlot ( 0 );
}
return m_HotbarSlots . GetSlot ( a_SlotNum );
2013-05-19 18:22:37 +00:00
}
2017-05-24 08:09:58 +02:00
const cItem & cInventory :: GetShieldSlot () const
{
return m_ShieldSlots . GetSlot ( 0 );
}
2013-05-19 18:22:37 +00:00
const cItem & cInventory :: GetEquippedItem ( void ) const
{
2013-05-24 07:30:39 +00:00
return GetHotbarSlot ( m_EquippedSlotNum );
2012-06-14 13:06:06 +00:00
}
2013-05-19 18:22:37 +00:00
void cInventory :: SetEquippedSlotNum ( int a_SlotNum )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
if (( a_SlotNum < 0 ) || ( a_SlotNum >= invHotbarCount ))
2012-09-20 13:25:54 +00:00
{
2013-05-24 07:30:39 +00:00
LOGWARNING ( "%s: requesting invalid slot index: %d out of %d. Setting 0 instead." , __FUNCTION__ , a_SlotNum , invHotbarCount - 1 );
2013-05-19 18:22:37 +00:00
m_EquippedSlotNum = 0 ;
2012-09-20 13:25:54 +00:00
}
else
{
2013-05-24 07:30:39 +00:00
m_EquippedSlotNum = a_SlotNum ;
2012-09-20 13:25:54 +00:00
}
2012-06-14 13:06:06 +00:00
}
2013-05-19 18:22:37 +00:00
bool cInventory :: DamageEquippedItem ( short a_Amount )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
return DamageItem ( invHotbarOffset + m_EquippedSlotNum , a_Amount );
2012-06-14 13:06:06 +00:00
}
2013-07-26 19:50:06 +00:00
int cInventory :: ChangeSlotCount ( int a_SlotNum , int a_AddToCount )
{
int GridSlotNum = 0 ;
cItemGrid * Grid = GetGridForSlotNum ( a_SlotNum , GridSlotNum );
2014-10-20 21:55:07 +01:00
if ( Grid == nullptr )
2013-07-26 19:50:06 +00:00
{
LOGWARNING ( "%s: invalid slot number, expected 0 .. %d, got %d; ignoring" , __FUNCTION__ , invNumSlots , a_SlotNum );
return - 1 ;
}
return Grid -> ChangeSlotCount ( GridSlotNum , a_AddToCount );
}
2013-05-19 18:22:37 +00:00
bool cInventory :: DamageItem ( int a_SlotNum , short a_Amount )
2012-08-24 07:58:26 +00:00
{
2013-05-24 07:30:39 +00:00
if (( a_SlotNum < 0 ) || ( a_SlotNum >= invNumSlots ))
2013-05-19 18:22:37 +00:00
{
2013-05-24 07:30:39 +00:00
LOGWARNING ( "%s: requesting an invalid slot index: %d out of %d" , __FUNCTION__ , a_SlotNum , invNumSlots - 1 );
2013-05-19 18:22:37 +00:00
return false ;
}
2014-07-23 16:32:09 +02:00
if ( a_Amount <= 0 )
{
return false ;
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
int GridSlotNum = 0 ;
cItemGrid * Grid = GetGridForSlotNum ( a_SlotNum , GridSlotNum );
2014-10-20 21:55:07 +01:00
if ( Grid == nullptr )
2013-05-19 18:22:37 +00:00
{
2013-05-24 07:30:39 +00:00
LOGWARNING ( "%s(%d, %d): requesting an invalid grid, ignoring." , __FUNCTION__ , a_SlotNum , a_Amount );
return false ;
}
if ( ! Grid -> DamageItem ( GridSlotNum , a_Amount ))
{
// The item has been damaged, but did not break yet
2014-05-07 20:59:25 +02:00
SendSlot ( a_SlotNum );
2013-05-19 18:22:37 +00:00
return false ;
}
2016-02-05 23:45:45 +02:00
2013-05-19 18:22:37 +00:00
// The item has broken, remove it:
2013-10-18 18:01:19 +02:00
Grid -> EmptySlot ( GridSlotNum );
2013-05-19 18:22:37 +00:00
return true ;
2012-08-24 07:58:26 +00:00
}
2013-05-24 07:30:39 +00:00
void cInventory :: CopyToItems ( cItems & a_Items )
{
m_ArmorSlots . CopyToItems ( a_Items );
m_InventorySlots . CopyToItems ( a_Items );
m_HotbarSlots . CopyToItems ( a_Items );
}
2012-08-24 08:04:58 +00:00
void cInventory :: SendSlot ( int a_SlotNum )
2012-06-14 13:06:06 +00:00
{
2013-05-19 18:22:37 +00:00
cItem Item ( GetSlot ( a_SlotNum ));
if ( Item . IsEmpty ())
2012-06-14 13:06:06 +00:00
{
2013-05-19 18:22:37 +00:00
// Sanitize items that are not completely empty (ie. count == 0, but type != empty)
Item . Empty ();
2012-06-14 13:06:06 +00:00
}
2015-07-29 09:04:03 -06:00
m_Owner . GetClientHandle () -> SendInventorySlot ( 0 , static_cast < short > ( a_SlotNum + 5 ), Item ); // Slots in the client are numbered "+ 5" because of crafting grid and result
2012-08-11 19:54:57 +00:00
}
2013-05-24 07:30:39 +00:00
/*
2012-08-19 11:51:17 +00:00
int cInventory::MoveItem(short a_ItemType, short a_ItemDamage, int a_Count, int a_BeginSlot, int a_EndSlot)
2012-08-11 19:54:57 +00:00
{
int res = 0;
for (int i = a_BeginSlot; i <= a_EndSlot; i++)
{
if (
m_Slots[i].IsEmpty() ||
2013-01-12 04:46:01 +00:00
((m_Slots[i].m_ItemType == a_ItemType) && (m_Slots[i].m_ItemDamage == a_ItemDamage))
2012-08-11 19:54:57 +00:00
)
{
int MaxCount = ItemHandler(a_ItemType)->GetMaxStackSize();
ASSERT(m_Slots[i].m_ItemCount <= MaxCount);
2012-08-14 08:33:09 +00:00
int NumToMove = std::min(a_Count, MaxCount - m_Slots[i].m_ItemCount);
2012-08-11 19:54:57 +00:00
m_Slots[i].m_ItemCount += NumToMove;
2013-01-12 04:46:01 +00:00
m_Slots[i].m_ItemDamage = a_ItemDamage;
m_Slots[i].m_ItemType = a_ItemType;
2012-08-11 19:54:57 +00:00
SendSlot(i);
res += NumToMove;
a_Count -= NumToMove;
if (a_Count <= 0)
{
// No more items to distribute
return res;
}
}
} // for i - m_Slots[]
// No more space to distribute to
return res;
}
2013-05-24 07:30:39 +00:00
*/
2012-08-11 19:54:57 +00:00
2013-05-24 07:30:39 +00:00
int cInventory :: ArmorSlotNumToEntityEquipmentID ( short a_ArmorSlotNum )
2013-05-19 18:22:37 +00:00
{
2013-05-24 07:30:39 +00:00
switch ( a_ArmorSlotNum )
2013-05-19 18:22:37 +00:00
{
2013-05-24 07:30:39 +00:00
case 0 : return 4 ; // Helmet
case 1 : return 3 ; // Chestplate
case 2 : return 2 ; // Leggings
case 3 : return 1 ; // Boots
2013-05-19 18:22:37 +00:00
}
2013-05-24 07:30:39 +00:00
LOGWARN ( "%s: invalid armor slot number: %d" , __FUNCTION__ , a_ArmorSlotNum );
2013-05-19 18:22:37 +00:00
return 0 ;
}
2013-05-24 07:30:39 +00:00
#if 0
2015-05-09 11:16:56 +02:00
bool cInventory::AddToBar(cItem & a_Item, const int a_Offset, const int a_Size, bool * a_bChangedSlots, int a_Mode /* = 0 */)
2012-06-14 13:06:06 +00:00
{
// Fill already present stacks
2014-07-21 15:19:48 +02:00
if (a_Mode < 2)
2012-06-14 13:06:06 +00:00
{
2012-10-24 12:48:25 +00:00
int MaxStackSize = cItemHandler::GetItemHandler(a_Item.m_ItemType)->GetMaxStackSize();
2014-07-20 23:10:31 +02:00
for (int i = 0; i < a_Size; i++)
2012-06-14 13:06:06 +00:00
{
2014-12-05 12:56:53 +01:00
if (
(m_Slots[i + a_Offset].m_ItemType == a_Item.m_ItemType) &&
(m_Slots[i + a_Offset].m_ItemCount < MaxStackSize) &&
(m_Slots[i + a_Offset].m_ItemDamage == a_Item.m_ItemDamage)
)
2012-06-14 13:06:06 +00:00
{
2012-10-24 12:48:25 +00:00
int NumFree = MaxStackSize - m_Slots[i + a_Offset].m_ItemCount;
2014-07-21 15:19:48 +02:00
if (NumFree >= a_Item.m_ItemCount)
2012-06-14 13:06:06 +00:00
{
2014-07-21 15:19:48 +02:00
// printf("1. Adding %i items ( free: %i)\n", a_Item.m_ItemCount, NumFree);
2012-06-14 13:06:06 +00:00
m_Slots[i + a_Offset].m_ItemCount += a_Item.m_ItemCount;
a_Item.m_ItemCount = 0;
a_bChangedSlots[i + a_Offset] = true;
break;
}
else
{
2014-07-21 15:19:48 +02:00
// printf("2. Adding %i items\n", NumFree);
2012-06-14 13:06:06 +00:00
m_Slots[i + a_Offset].m_ItemCount += (char)NumFree;
a_Item.m_ItemCount -= (char)NumFree;
a_bChangedSlots[i + a_Offset] = true;
}
}
}
}
2014-07-21 15:19:48 +02:00
if (a_Mode > 0)
2012-06-14 13:06:06 +00:00
{
// If we got more left, find first empty slot
2014-12-05 12:56:53 +01:00
for (int i = 0; (i < a_Size) && (a_Item.m_ItemCount > 0); i++)
2012-06-14 13:06:06 +00:00
{
2014-07-21 15:19:48 +02:00
if (m_Slots[i + a_Offset].m_ItemType == -1)
2012-06-14 13:06:06 +00:00
{
m_Slots[i + a_Offset] = a_Item;
a_Item.m_ItemCount = 0;
a_bChangedSlots[i + a_Offset] = true;
}
}
}
return true;
}
2013-05-24 07:30:39 +00:00
#endif
2012-06-14 13:06:06 +00:00
2014-02-17 16:27:12 +02:00
void cInventory :: UpdateItems ( void )
{
const cItem & Slot = GetEquippedItem ();
2015-06-30 15:50:15 +01:00
if ( ! Slot . IsEmpty ())
2014-02-17 16:27:12 +02:00
{
2015-06-30 15:50:15 +01:00
ItemHandler ( Slot . m_ItemType ) -> OnUpdate ( m_Owner . GetWorld (), & m_Owner , Slot );
2014-02-17 16:27:12 +02:00
}
}
2012-06-14 13:06:06 +00:00
void cInventory :: SaveToJson ( Json :: Value & a_Value )
{
2013-05-24 07:30:39 +00:00
// The JSON originally included the 4 crafting slots and the result, so we have to put empty items there, too:
cItem EmptyItem ;
Json :: Value EmptyItemJson ;
EmptyItem . GetJson ( EmptyItemJson );
for ( int i = 0 ; i < 5 ; i ++ )
{
a_Value . append ( EmptyItemJson );
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
// The 4 armor slots follow:
for ( int i = 0 ; i < invArmorCount ; i ++ )
2012-06-14 13:06:06 +00:00
{
Json :: Value JSON_Item ;
2013-05-24 07:30:39 +00:00
m_ArmorSlots . GetSlot ( i ). GetJson ( JSON_Item );
a_Value . append ( JSON_Item );
}
// Next comes the main inventory:
for ( int i = 0 ; i < invInventoryCount ; i ++ )
{
Json :: Value JSON_Item ;
m_InventorySlots . GetSlot ( i ). GetJson ( JSON_Item );
a_Value . append ( JSON_Item );
}
2017-05-24 08:09:58 +02:00
// The hotbar:
2013-05-24 07:30:39 +00:00
for ( int i = 0 ; i < invHotbarCount ; i ++ )
{
Json :: Value JSON_Item ;
m_HotbarSlots . GetSlot ( i ). GetJson ( JSON_Item );
a_Value . append ( JSON_Item );
2012-06-14 13:06:06 +00:00
}
2017-05-24 08:09:58 +02:00
// Shield slot is the last
Json :: Value JSON_Item ;
m_ShieldSlots . GetSlot ( 0 ). GetJson ( JSON_Item );
a_Value . append ( JSON_Item );
2012-06-14 13:06:06 +00:00
}
bool cInventory :: LoadFromJson ( Json :: Value & a_Value )
{
int SlotIdx = 0 ;
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
for ( Json :: Value :: iterator itr = a_Value . begin (); itr != a_Value . end (); ++ itr , SlotIdx ++ )
2012-06-14 13:06:06 +00:00
{
2013-05-24 07:30:39 +00:00
cItem Item ;
Item . FromJson ( * itr );
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
// The JSON originally included the 4 crafting slots and the result slot, so we need to skip the first 5 items:
if ( SlotIdx < 5 )
{
continue ;
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
// If we loaded all the slots, stop now, even if the JSON has more:
if ( SlotIdx - 5 >= invNumSlots )
2013-05-19 18:22:37 +00:00
{
break ;
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
int GridSlotNum = 0 ;
cItemGrid * Grid = GetGridForSlotNum ( SlotIdx - 5 , GridSlotNum );
2014-10-20 21:55:07 +01:00
ASSERT ( Grid != nullptr );
2013-05-24 07:30:39 +00:00
Grid -> SetSlot ( GridSlotNum , Item );
} // for itr - a_Value[]
2012-06-14 13:06:06 +00:00
return true ;
}
2013-05-24 07:30:39 +00:00
const cItemGrid * cInventory :: GetGridForSlotNum ( int a_SlotNum , int & a_GridSlotNum ) const
{
ASSERT ( a_SlotNum >= 0 );
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
if ( a_SlotNum < invArmorCount )
{
a_GridSlotNum = a_SlotNum ;
return & m_ArmorSlots ;
}
a_SlotNum -= invArmorCount ;
if ( a_SlotNum < invInventoryCount )
{
a_GridSlotNum = a_SlotNum ;
return & m_InventorySlots ;
}
2017-05-24 08:09:58 +02:00
a_SlotNum -= invInventoryCount ;
if ( a_SlotNum < invHotbarCount )
{
a_GridSlotNum = a_SlotNum ;
return & m_HotbarSlots ;
}
a_GridSlotNum = a_SlotNum - invHotbarCount ;
return & m_ShieldSlots ;
2013-05-24 07:30:39 +00:00
}
cItemGrid * cInventory :: GetGridForSlotNum ( int a_SlotNum , int & a_GridSlotNum )
{
ASSERT ( a_SlotNum >= 0 );
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
if ( a_SlotNum < invArmorCount )
{
a_GridSlotNum = a_SlotNum ;
return & m_ArmorSlots ;
}
a_SlotNum -= invArmorCount ;
if ( a_SlotNum < invInventoryCount )
{
a_GridSlotNum = a_SlotNum ;
return & m_InventorySlots ;
}
2017-05-24 08:09:58 +02:00
a_SlotNum -= invInventoryCount ;
if ( a_SlotNum < invHotbarCount )
{
a_GridSlotNum = a_SlotNum ;
return & m_HotbarSlots ;
}
a_GridSlotNum = a_SlotNum - invHotbarCount ;
return & m_ShieldSlots ;
2013-05-24 07:30:39 +00:00
}
void cInventory :: OnSlotChanged ( cItemGrid * a_ItemGrid , int a_SlotNum )
{
// Send the neccessary updates to whoever needs them
2016-02-05 23:45:45 +02:00
2016-02-07 19:07:14 +02:00
if ( ! m_Owner . IsTicking ())
2013-05-24 07:30:39 +00:00
{
// Owner is not (yet) valid, skip for now
return ;
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
// Armor update needs broadcast to other players:
cWorld * World = m_Owner . GetWorld ();
2014-10-20 21:55:07 +01:00
if (( a_ItemGrid == & m_ArmorSlots ) && ( World != nullptr ))
2013-05-24 07:30:39 +00:00
{
World -> BroadcastEntityEquipment (
2015-08-05 01:24:59 +03:00
m_Owner , static_cast < short > ( ArmorSlotNumToEntityEquipmentID ( static_cast < short > ( a_SlotNum ))),
2013-05-24 07:30:39 +00:00
m_ArmorSlots . GetSlot ( a_SlotNum ), m_Owner . GetClientHandle ()
);
}
2014-07-23 16:32:09 +02:00
// Broadcast the Equipped Item, if the Slot is changed.
if (( a_ItemGrid == & m_HotbarSlots ) && ( m_EquippedSlotNum == a_SlotNum ))
{
m_Owner . GetWorld () -> BroadcastEntityEquipment ( m_Owner , 0 , GetEquippedItem (), m_Owner . GetClientHandle ());
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
// Convert the grid-local a_SlotNum to our global SlotNum:
int Base = 0 ;
if ( a_ItemGrid == & m_ArmorSlots )
{
Base = invArmorOffset ;
}
else if ( a_ItemGrid == & m_InventorySlots )
{
Base = invInventoryOffset ;
}
else if ( a_ItemGrid == & m_HotbarSlots )
{
Base = invHotbarOffset ;
}
2017-12-21 16:01:24 +00:00
else if ( a_ItemGrid == & m_ShieldSlots )
2017-12-21 11:55:23 +00:00
{
Base = invShieldOffset ;
}
2013-05-24 07:30:39 +00:00
else
{
ASSERT ( ! "Unknown ItemGrid calling OnSlotChanged()" );
return ;
}
2016-02-05 23:45:45 +02:00
2013-05-24 07:30:39 +00:00
SendSlot ( Base + a_SlotNum );
}