@ -42,6 +42,7 @@ All rights reserved.
# include "Menu.h"
# include "Ability.h"
# include "AttributableStat.h"
# include <numeric>
INCLUDE_game
INCLUDE_DATA
@ -51,7 +52,7 @@ safemap<std::string,ItemInfo>ITEM_DATA;
safemap < std : : string , ItemScript > ITEM_SCRIPTS ;
safemap < std : : string , std : : set < std : : string > > ITEM_CATEGORIES ;
std : : shared_ptr < Item > Item : : BLANK = std : : make_shared < Item > ( ) ;
std : : map < IT , std : : shared_ptr < Item > > Inventory : : _inventory ;
std : : multim ap < IT , std : : shared_ptr < Item > > Inventory : : _inventory ;
std : : map < ITCategory , std : : vector < std : : shared_ptr < Item > > > Inventory : : sortedInv ;
std : : vector < ItemOverlay > ItemOverlay : : items ;
std : : map < std : : string , ItemSet > ItemSet : : sets ;
@ -358,31 +359,52 @@ Item::Item(uint32_t amt,IT item,uint8_t enhancementLevel)
void Inventory : : AddItem ( IT it , uint32_t amt , bool monsterDrop ) {
if ( ! ITEM_DATA . count ( it ) ) ERR ( " Item " < < std : : quoted ( it ) < < " does not exist in Item Database! " ) ;
if ( ITEM_DATA [ it ] . IsEquippable ( ) ) { //Do not stack equips!
for ( uint32_t i = 0 ; i < amt ; i + + ) {
InsertIntoSortedInv ( ( * _inventory . insert ( { it , std : : make_shared < Item > ( amt , it ) } ) ) . second ) ;
}
goto SkipAddingStackableItem ;
}
else
//There are two places to manipulate items in (Both the sorted inventory and the actual inventory)
if ( ! _inventory . count ( it ) ) {
_inventory [ it ] = std : : make_shared < Item > ( amt , it ) ;
InsertIntoSortedInv ( it ) ;
InsertIntoSortedInv ( ( * _inventory . insert ( { it , std : : make_shared < Item > ( amt , it ) } ) ) . second ) ;
} else {
_inventory . at ( it ) - > amt + = amt ;
auto inventory = _inventory . equal_range ( it ) ;
std : : accumulate ( inventory . first , inventory . second , 0 , [ & ] ( int counter , std : : pair < IT , std : : shared_ptr < Item > > item ) {
( * item . second ) . amt + = amt ;
if ( counter > = 1 ) ERR ( " WARNING! We should not have more than 1 instance of a stackable item! " ) ;
return counter + 1 ;
} ) ;
}
SkipAddingStackableItem :
InsertIntoStageInventoryCategory ( it , amt , monsterDrop ) ;
}
std : : shared_ptr < Item > Inventory : : CopyItem ( IT it ) {
if ( ! _inventory . count ( it ) ) return std : : make_shared < Item > ( * Item : : BLANK ) ;
return std : : make_shared < Item > ( * _inventory . at ( it ) ) ;
std : : vector < std : : shared_ptr < Item > > Inventory : : CopyItem ( IT it ) {
if ( ! _inventory . count ( it ) ) return { } ;
std : : vector < std : : shared_ptr < Item > > copiedItems ;
auto inventory = _inventory . equal_range ( it ) ;
std : : for_each ( inventory . first , inventory . second , [ & ] ( std : : pair < IT , std : : shared_ptr < Item > > it ) { copiedItems . push_back ( std : : make_shared < Item > ( * it . second ) ) ; } ) ;
return copiedItems ;
}
std : : weak_ptr < Item > Inventory : : GetItem ( IT it ) {
if ( ! _inventory . count ( it ) ) return Item : : BLANK ;
return _inventory . at ( it ) ;
std : : vector < std : : weak_ptr < Item > > Inventory : : GetItem ( IT it ) {
if ( ! _inventory . count ( it ) ) return { } ;
std : : vector < std : : weak_ptr < Item > > items ;
auto inventory = _inventory . equal_range ( it ) ;
std : : for_each ( inventory . first , inventory . second , [ & ] ( std : : pair < IT , std : : shared_ptr < Item > > it ) { items . push_back ( it . second ) ; } ) ;
return items ;
}
uint32_t Inventory : : GetItemCount ( IT it ) {
if ( ! _inventory . count ( it ) ) {
return 0 ;
} else {
return _inventory . at ( it ) - > Amt ( ) ;
auto inventory = _inventory . equal_range ( it ) ;
return std : : accumulate ( inventory . first , inventory . second , 0 , [ ] ( int val , std : : pair < IT , std : : shared_ptr < Item > > it ) { return val + ( * it . second ) . Amt ( ) ; } ) ;
}
}
@ -392,14 +414,14 @@ bool Inventory::UseItem(IT it,uint32_t amt){
//There are two places to manipulate items in (Both the sorted inventory and the actual inventory)
for ( uint32_t i = 0 ; i < amt ; i + + ) {
if ( ExecuteAction ( it ) ) {
return RemoveItem ( it ) ;
return RemoveItem ( GetItem ( it ) [ 0 ] ) ;
}
}
return false ;
}
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory.
bool Inventory : : RemoveItem ( IT it , ITCategory inventory , uint32_t amt ) {
bool Inventory : : RemoveItem ( std : : weak_ptr < Item > itemRef , ITCategory inventory , uint32_t amt ) {
# pragma region Calculate Inventory to Manipulate
std : : vector < std : : shared_ptr < Item > > & inv = sortedInv . at ( inventory ) ;
bool eraseFromLootWindow = false ;
@ -412,13 +434,13 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){
eraseFromLootWindow = true ;
}
int count = 0 ;
for ( std : : shared _ptr< Item > item : inv ) {
if ( item = = it ) break ;
for ( std : : weak _ptr< Item > item : inv ) {
if ( item = = itemRef ) break ;
count + + ;
}
# pragma endregion
uint32_t itemAmt = GetItemCount ( it ) ;
uint32_t itemAmt = GetItemCount ( itemRef . lock ( ) - > ActualName ( ) ) ;
if ( inventory = = " Monster Loot " | | inventory = = " Stage Loot " ) {
itemAmt = inv . at ( count ) - > Amt ( ) ;
}
@ -429,7 +451,7 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){
if ( amt > = itemAmt ) {
inv . erase ( inv . begin ( ) + count ) ; //Clears it from the detected sorted inventory as well!
if ( ! eraseFromLootWindow ) { //We must clear out the item AFTER we've updated context-sensitive inventories because they may be borrowing a ref from this structure!!!
_inventory . erase ( it ) ;
_inventory . erase ( itemRef . lock ( ) - > ActualName ( ) ) ;
}
//Callback for GUI inventories.
@ -437,28 +459,28 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){
return true ;
} else {
if ( ! eraseFromLootWindow ) {
_inventory . at ( it ) - > amt - = amt ;
itemRef . lock ( ) - > amt - = amt ;
} else {
inv . at ( count ) - > amt - = amt ; //Don't touch the sorted inventory unless this is monster loot or stage loot because there's only "1" of this item in the entry list.
itemRef . lock ( ) - > amt - = amt ; //Don't touch the sorted inventory unless this is monster loot or stage loot because there's only "1" of this item in the entry list.
}
return false ;
}
}
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory.
bool Inventory : : RemoveItem ( IT it , uint32_t amt ) {
ITCategory cat = ITEM_DATA [ it ] . category ;
return RemoveItem ( it , cat , amt ) ;
bool Inventory : : RemoveItem ( std : : weak_ptr < Item > itemRef , uint32_t amt ) {
ITCategory cat = itemRef . lock ( ) - > Category ( ) ;
return RemoveItem ( itemRef , cat , amt ) ;
}
const std : : vector < std : : shared_ptr < Item > > & Inventory : : get ( ITCategory itemCategory ) {
return sortedInv . at ( itemCategory ) ;
}
void Inventory : : InsertIntoSortedInv ( IT item ) {
sortedInv . at ( ITEM_DATA [ item ] . category ) . push_back ( _inventory [ item ] ) ;
void Inventory : : InsertIntoSortedInv ( std : : shared_ptr < Item > itemRef ) {
sortedInv . at ( itemRef - > Category ( ) ) . push_back ( itemRef ) ;
//This should be a callback to menus that we need to update the interface with another item slot since a new one has appeared.
Menu : : InventorySlotsUpdated ( ITEM_DATA [ item ] . category ) ;
Menu : : InventorySlotsUpdated ( itemRef - > Category ( ) ) ;
}
void Inventory : : InsertIntoStageInventoryCategory ( IT item , uint32_t amt , bool monsterDrop ) {
@ -467,7 +489,7 @@ void Inventory::InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monst
stageInventoryCategory = " Monster Loot " ;
}
std : : vector < std : : shared_ptr < Item > > & inv = sortedInv . at ( stageInventoryCategory ) ;
std : : vector < std : : shared_ptr < Item > > : : iterator it = std : : find ( inv . begin ( ) , inv . end ( ) , std : : make_shared < Item > ( amt , item ) ) ;
std : : vector < std : : shared_ptr < Item > > : : iterator it = std : : find ( inv . begin ( ) , inv . end ( ) , std : : make_shared < Item > ( amt , item ) ) ; //Uses operator== to compare if this item does exist in a stage/monster loot inventory already. We just make an in-place shared pointer of an item to compare with.
if ( it ! = inv . end ( ) ) {
( * it ) - > amt + = amt ;
} else {
@ -491,8 +513,8 @@ bool Inventory::SwapItems(ITCategory itemCategory,uint32_t slot1,uint32_t slot2)
//The inventory is too small, so expand out blank slots to accomodate.
inv . resize ( largestSlot + size_t ( 1 ) ) ;
}
std : : shared _ptr< Item > item1 = inv . at ( slot1 ) ;
std : : shared _ptr< Item > item2 = inv . at ( slot2 ) ;
std : : weak _ptr< Item > item1 = inv . at ( slot1 ) ;
std : : weak _ptr< Item > item2 = inv . at ( slot2 ) ;
std : : swap ( item1 , item2 ) ;
return true ;
}
@ -609,7 +631,7 @@ void Inventory::Clear(ITCategory itemCategory){
if ( itemCategory = = " Monster Loot " | | itemCategory = = " Stage Loot " ) { //These do not affect the actual inventory, we just clear the lists.
itemQuantity = item - > Amt ( ) ;
}
RemoveItem ( item - > ActualName ( ) , itemCategory , uint32_t ( itemQuantity ) ) ;
RemoveItem ( item , itemCategory , uint32_t ( itemQuantity ) ) ;
}
}
@ -707,7 +729,7 @@ EquipSlot Inventory::GetSlotEquippedIn(const std::weak_ptr<Item>it){
EquipSlot slot = EquipSlot ( i ) ;
std : : weak_ptr < Item > equip = GetEquip ( slot ) ;
if ( equip . expired ( ) ) continue ;
if ( equip . lock ( ) - > ActualName ( ) = = it . lock ( ) - > ActualName ( ) ) return slot ;
if ( & * equip . lock ( ) = = & * it . lock ( ) ) return slot ;
}
return EquipSlot : : NONE ;
} ;
@ -782,7 +804,7 @@ void Item::EnhanceItem(uint8_t qty){
const CraftingRequirement & consumedResources = GetEnhancementInfo ( ) [ EnhancementLevel ( ) ] . craftingRequirement ;
for ( const auto & [ name , amt ] : consumedResources . GetItems ( ) ) {
Inventory : : RemoveItem ( name , amt ) ;
Inventory : : RemoveItem ( Inventory : : GetItem ( name ) [ 0 ] , amt ) ;
}
game - > GetPlayer ( ) - > SetMoney ( game - > GetPlayer ( ) - > GetMoney ( ) - consumedResources . GetCost ( ) ) ;
} else { //This is a craftable, so we have to give the player the item they crafted.
@ -791,7 +813,7 @@ void Item::EnhanceItem(uint8_t qty){
const CraftingRequirement & consumedResources = GetEnhancementInfo ( ) [ 1 ] . craftingRequirement ;
for ( const auto & [ name , amt ] : consumedResources . GetItems ( ) ) {
Inventory : : RemoveItem ( name , amt ) ;
Inventory : : RemoveItem ( Inventory : : GetItem ( name ) [ 0 ] , amt ) ;
}
game - > GetPlayer ( ) - > SetMoney ( game - > GetPlayer ( ) - > GetMoney ( ) - consumedResources . GetCost ( ) ) ;
}
@ -871,7 +893,7 @@ void Item::SetAmt(uint32_t newAmt){
}
const std : : weak_ptr < Item > Inventory : : GetInventorySlot ( ITCategory itemCategory , size_t slot ) {
return GetItem ( get ( itemCategory ) . at ( slot ) - > ActualName ( ) ) ;
return GetItem ( get ( itemCategory ) . at ( slot ) - > ActualName ( ) ) [ 0 ] ;
}
bool Item : : IsBlank ( std : : shared_ptr < Item > item ) {