2022-05-09 00:57:36 +00:00
# include "InventoryComponent.h"
2021-12-05 17:54:36 +00:00
# include <sstream>
# include "Entity.h"
# include "Item.h"
# include "Game.h"
# include "dLogger.h"
# include "CDClientManager.h"
# include "../dWorldServer/ObjectIDManager.h"
# include "MissionComponent.h"
# include "GameMessages.h"
# include "SkillComponent.h"
# include "Character.h"
# include "EntityManager.h"
# include "ItemSet.h"
# include "Player.h"
# include "PetComponent.h"
2023-06-26 17:36:36 +00:00
# include "PossessionComponent.h"
2021-12-05 17:54:36 +00:00
# include "PossessableComponent.h"
# include "ModuleAssemblyComponent.h"
2023-06-08 15:29:17 +00:00
# include "HavokVehiclePhysicsComponent.h"
2021-12-05 17:54:36 +00:00
# include "CharacterComponent.h"
# include "dZoneManager.h"
# include "PropertyManagementComponent.h"
2022-02-10 05:21:10 +00:00
# include "DestroyableComponent.h"
2022-06-18 07:03:27 +00:00
# include "dConfig.h"
2022-07-17 01:36:09 +00:00
# include "eItemType.h"
2022-09-02 18:49:19 +00:00
# include "eUnequippableActiveType.h"
2022-12-21 22:33:41 +00:00
# include "CppScripts.h"
2023-01-22 23:38:47 +00:00
# include "eMissionTaskType.h"
2023-05-02 22:39:21 +00:00
# include "eStateChangeType.h"
# include "eUseItemResponse.h"
2021-12-05 17:54:36 +00:00
2023-03-17 14:36:21 +00:00
# include "CDComponentsRegistryTable.h"
# include "CDInventoryComponentTable.h"
# include "CDScriptComponentTable.h"
# include "CDObjectSkillsTable.h"
# include "CDSkillBehaviorTable.h"
2023-06-18 00:20:05 +00:00
InventoryComponent : : InventoryComponent ( Entity * parent , tinyxml2 : : XMLDocument * document ) : Component ( parent ) {
2021-12-05 17:54:36 +00:00
this - > m_Dirty = true ;
2023-06-27 09:01:43 +00:00
this - > m_Equipped . clear ( ) ;
this - > m_Pushed . clear ( ) ;
2021-12-05 17:54:36 +00:00
this - > m_Consumable = LOT_NULL ;
2023-06-27 09:01:43 +00:00
this - > m_Pets . clear ( ) ;
2021-12-05 17:54:36 +00:00
const auto lot = parent - > GetLOT ( ) ;
2023-06-28 08:20:41 +00:00
if ( m_ParentEntity - > IsPlayer ( ) ) {
2021-12-05 17:54:36 +00:00
LoadXml ( document ) ;
CheckProxyIntegrity ( ) ;
return ;
}
2023-03-17 14:36:21 +00:00
auto * compRegistryTable = CDClientManager : : Instance ( ) . GetTable < CDComponentsRegistryTable > ( ) ;
2023-03-04 07:16:37 +00:00
const auto componentId = compRegistryTable - > GetByIDAndType ( lot , eReplicaComponentType : : INVENTORY ) ;
2021-12-05 17:54:36 +00:00
2023-03-17 14:36:21 +00:00
auto * inventoryComponentTable = CDClientManager : : Instance ( ) . GetTable < CDInventoryComponentTable > ( ) ;
2023-06-28 08:20:41 +00:00
auto items = inventoryComponentTable - > Query ( [ & componentId ] ( const CDInventoryComponent entry ) { return entry . id = = componentId ; } ) ;
2021-12-05 17:54:36 +00:00
auto slot = 0u ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
for ( const auto & item : items ) {
if ( ! item . equip | | ! Inventory : : IsValidItem ( item . itemid ) ) {
2021-12-05 17:54:36 +00:00
continue ;
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
const LWOOBJID id = ObjectIDManager : : Instance ( ) - > GenerateObjectID ( ) ;
const auto & info = Inventory : : FindItemComponent ( item . itemid ) ;
2022-01-13 03:48:27 +00:00
2023-06-27 09:01:43 +00:00
UpdateSlot ( info . equipLocation , EquippedItem ( id , static_cast < LOT > ( item . itemid ) , item . count , slot + + ) ) ;
2022-09-02 18:49:19 +00:00
2022-07-30 00:00:36 +00:00
// Equip this items proxies.
auto subItems = info . subItems ;
2022-09-02 18:49:19 +00:00
2022-07-30 00:00:36 +00:00
subItems . erase ( std : : remove_if ( subItems . begin ( ) , subItems . end ( ) , : : isspace ) , subItems . end ( ) ) ;
2022-09-02 18:49:19 +00:00
2023-06-29 17:44:06 +00:00
if ( subItems . empty ( ) ) continue ;
2023-06-28 08:20:41 +00:00
const auto subItemsSplit = GeneralUtils : : SplitString ( subItems , ' , ' ) ;
2022-09-02 18:49:19 +00:00
2023-06-28 08:20:41 +00:00
for ( const auto & proxyLotAsString : subItemsSplit ) {
LOT proxyLot ;
if ( GeneralUtils : : TryParse ( proxyLotAsString , proxyLot ) ) {
Game : : logger - > Log ( " InventoryComponent " , " Failed to parse %s to lot for entity %i:%llu " , proxyLotAsString . c_str ( ) , m_ParentEntity - > GetLOT ( ) , m_ParentEntity - > GetObjectID ( ) ) ;
continue ;
}
2022-09-02 18:49:19 +00:00
2023-06-28 08:20:41 +00:00
const auto & proxyInfo = Inventory : : FindItemComponent ( proxyLot ) ;
const LWOOBJID proxyId = ObjectIDManager : : Instance ( ) - > GenerateObjectID ( ) ;
2022-09-02 18:49:19 +00:00
2023-06-28 08:20:41 +00:00
// Use item.count since we equip item.count number of the item this is a requested proxy of
UpdateSlot ( proxyInfo . equipLocation , EquippedItem ( proxyId , proxyLot , item . count , slot + + ) ) ;
2022-07-30 00:00:36 +00:00
}
2021-12-05 17:54:36 +00:00
}
}
2022-07-28 13:39:57 +00:00
Inventory * InventoryComponent : : GetInventory ( const eInventoryType type ) {
2021-12-05 17:54:36 +00:00
const auto index = m_Inventories . find ( type ) ;
2023-06-28 08:20:41 +00:00
if ( index ! = m_Inventories . end ( ) ) return index - > second ;
2021-12-05 17:54:36 +00:00
// Create new empty inventory
uint32_t size = 240u ;
2022-07-28 13:39:57 +00:00
switch ( type ) {
2021-12-05 17:54:36 +00:00
case eInventoryType : : ITEMS :
size = 20u ;
break ;
2022-04-13 08:49:55 +00:00
case eInventoryType : : VAULT_MODELS :
2021-12-05 17:54:36 +00:00
case eInventoryType : : VAULT_ITEMS :
size = 40u ;
break ;
2022-04-23 11:16:10 +00:00
case eInventoryType : : VENDOR_BUYBACK :
size = 27u ;
break ;
2021-12-05 17:54:36 +00:00
default :
break ;
}
2023-06-28 08:20:41 +00:00
auto * inventory = new Inventory ( type , size , std : : vector < Item * > ( ) , this ) ;
2021-12-05 17:54:36 +00:00
m_Inventories . insert_or_assign ( type , inventory ) ;
return inventory ;
}
2022-07-28 13:39:57 +00:00
uint32_t InventoryComponent : : GetLotCount ( const LOT lot ) const {
2021-12-05 17:54:36 +00:00
uint32_t count = 0 ;
2023-06-28 08:20:41 +00:00
for ( const auto & [ inventoryId , inventory ] : m_Inventories ) {
count + = inventory - > GetLotCount ( lot ) ;
2021-12-05 17:54:36 +00:00
}
return count ;
}
2022-07-28 13:39:57 +00:00
uint32_t InventoryComponent : : GetLotCountNonTransfer ( LOT lot ) const {
2021-12-05 17:54:36 +00:00
uint32_t count = 0 ;
2023-06-28 08:20:41 +00:00
for ( const auto [ inventoryId , inventory ] : m_Inventories ) {
if ( IsTransferInventory ( inventory - > GetType ( ) ) ) continue ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
count + = inventory - > GetLotCount ( lot ) ;
2021-12-05 17:54:36 +00:00
}
return count ;
}
void InventoryComponent : : AddItem (
const LOT lot ,
const uint32_t count ,
2022-04-24 03:35:34 +00:00
eLootSourceType lootSourceType ,
2021-12-05 17:54:36 +00:00
eInventoryType inventoryType ,
const std : : vector < LDFBaseData * > & config ,
const LWOOBJID parent ,
const bool showFlyingLoot ,
bool isModMoveAndEquip ,
const LWOOBJID subKey ,
const eInventoryType inventorySourceType ,
const int32_t sourceType ,
const bool bound ,
2022-07-28 13:39:57 +00:00
int32_t preferredSlot ) {
if ( count = = 0 ) {
2023-06-28 08:20:41 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Attempted to add 0 of item (%i) to the inventory of %i:%llu! " , lot , m_ParentEntity - > GetLOT ( ) , m_ParentEntity - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2022-07-28 13:39:57 +00:00
if ( ! Inventory : : IsValidItem ( lot ) ) {
if ( lot > 0 ) {
2023-06-28 08:20:41 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Attempted to add invalid item (%i) to the inventory of %i:%llu! " , lot , m_ParentEntity - > GetLOT ( ) , m_ParentEntity - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
}
return ;
}
2023-06-28 08:20:41 +00:00
if ( inventoryType = = INVALID ) inventoryType = Inventory : : FindInventoryTypeForLot ( lot ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
auto * missionComponent = m_ParentEntity - > GetComponent < MissionComponent > ( ) ;
2021-12-05 17:54:36 +00:00
auto * inventory = GetInventory ( inventoryType ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
// Config items cant stack as they are unique per item.
2022-07-28 13:39:57 +00:00
if ( ! config . empty ( ) | | bound ) {
2022-04-24 03:35:34 +00:00
const auto slot = preferredSlot ! = - 1 & & inventory - > IsSlotEmpty ( preferredSlot ) ? preferredSlot : inventory - > FindEmptySlot ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( slot = = - 1 ) {
2023-06-28 08:20:41 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Failed to find empty slot for inventory (%i) of %i:%llu! " , inventoryType , m_ParentEntity - > GetLOT ( ) , m_ParentEntity - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2022-01-13 03:48:27 +00:00
2022-04-23 12:13:06 +00:00
auto * item = new Item ( lot , inventory , slot , count , config , parent , showFlyingLoot , isModMoveAndEquip , subKey , bound , lootSourceType ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( missionComponent & & ! IsTransferInventory ( inventoryType ) ) {
missionComponent - > Progress ( eMissionTaskType : : GATHER , lot , LWOOBJID_EMPTY , " " , count , IsTransferInventory ( inventorySourceType ) ) ;
2021-12-05 17:54:36 +00:00
}
return ;
}
2023-06-28 08:20:41 +00:00
const auto & info = Inventory : : FindItemComponent ( lot ) ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
auto left = count ;
int32_t outOfSpace = 0 ;
auto stack = static_cast < uint32_t > ( info . stackSize ) ;
2023-06-28 08:20:41 +00:00
bool isBrick = inventoryType = = eInventoryType : : BRICKS | | ( stack = = 0 & & info . itemType = = eItemType : : BRICK ) ;
2022-11-30 09:04:46 +00:00
2022-06-12 18:44:45 +00:00
// info.itemType of 1 is item type brick
2022-11-30 09:04:46 +00:00
if ( isBrick ) {
2022-11-26 10:30:53 +00:00
stack = UINT32_MAX ;
2022-07-28 13:39:57 +00:00
} else if ( stack = = 0 ) {
2021-12-05 17:54:36 +00:00
stack = 1 ;
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
auto * existing = FindItemByLot ( lot , inventoryType ) ;
2023-06-28 08:20:41 +00:00
if ( existing ) {
2021-12-05 17:54:36 +00:00
const auto delta = std : : min < uint32_t > ( left , stack - existing - > GetCount ( ) ) ;
left - = delta ;
2022-04-24 03:35:34 +00:00
existing - > SetCount ( existing - > GetCount ( ) + delta , false , true , showFlyingLoot , lootSourceType ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( isModMoveAndEquip ) {
2021-12-05 17:54:36 +00:00
existing - > Equip ( ) ;
isModMoveAndEquip = false ;
}
}
2022-11-26 10:30:53 +00:00
// If we have some leftover and we aren't bricks, make a new stack
2022-11-30 09:04:46 +00:00
while ( left > 0 & & ( ! isBrick | | ( isBrick & & ! existing ) ) ) {
2021-12-05 17:54:36 +00:00
const auto size = std : : min ( left , stack ) ;
left - = size ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
int32_t slot ;
2022-07-28 13:39:57 +00:00
if ( preferredSlot ! = - 1 & & inventory - > IsSlotEmpty ( preferredSlot ) ) {
2021-12-05 17:54:36 +00:00
slot = preferredSlot ;
preferredSlot = - 1 ;
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
slot = inventory - > FindEmptySlot ( ) ;
}
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
if ( slot = = - 1 ) {
2023-06-09 08:28:01 +00:00
auto * player = dynamic_cast < Player * > ( GetParentEntity ( ) ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( ! player ) return ;
2021-12-05 17:54:36 +00:00
outOfSpace + = size ;
2022-07-28 13:39:57 +00:00
switch ( sourceType ) {
2021-12-05 17:54:36 +00:00
case 0 :
player - > SendMail ( LWOOBJID_EMPTY , " Darkflame Universe " , " Lost Reward " , " You received an item and didn't have room for it. " , lot , size ) ;
break ;
case 1 :
2022-07-28 13:39:57 +00:00
for ( size_t i = 0 ; i < size ; i + + ) {
2023-06-09 09:46:01 +00:00
GameMessages : : SendDropClientLoot ( this - > m_ParentEntity , this - > m_ParentEntity - > GetObjectID ( ) , lot , 0 , this - > m_ParentEntity - > GetPosition ( ) , 1 ) ;
2021-12-05 17:54:36 +00:00
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
break ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
default :
break ;
}
continue ;
}
2022-04-23 12:13:06 +00:00
auto * item = new Item ( lot , inventory , slot , size , { } , parent , showFlyingLoot , isModMoveAndEquip , subKey , false , lootSourceType ) ;
2021-12-05 17:54:36 +00:00
isModMoveAndEquip = false ;
}
2023-06-28 08:20:41 +00:00
if ( ! missionComponent | | IsTransferInventory ( inventoryType ) ) return ;
missionComponent - > Progress ( eMissionTaskType : : GATHER , lot , LWOOBJID_EMPTY , " " , count - outOfSpace , IsTransferInventory ( inventorySourceType ) ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : RemoveItem ( const LOT lot , const uint32_t count , eInventoryType inventoryType , const bool ignoreBound ) {
if ( count = = 0 ) {
2023-06-28 08:20:41 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Attempted to remove 0 of item (%i) from the inventory of %i:%llu! " , lot , m_ParentEntity - > GetLOT ( ) , m_ParentEntity - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2022-07-28 13:39:57 +00:00
if ( inventoryType = = INVALID ) {
2021-12-05 17:54:36 +00:00
inventoryType = Inventory : : FindInventoryTypeForLot ( lot ) ;
}
auto * inventory = GetInventory ( inventoryType ) ;
2023-06-28 08:20:41 +00:00
if ( ! inventory ) return ;
2021-12-05 17:54:36 +00:00
auto left = std : : min < uint32_t > ( count , inventory - > GetLotCount ( lot ) ) ;
2022-07-28 13:39:57 +00:00
while ( left > 0 ) {
2021-12-05 17:54:36 +00:00
auto * item = FindItemByLot ( lot , inventoryType , false , ignoreBound ) ;
2023-06-28 08:20:41 +00:00
if ( ! item ) break ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
const auto delta = std : : min < uint32_t > ( left , item - > GetCount ( ) ) ;
item - > SetCount ( item - > GetCount ( ) - delta ) ;
left - = delta ;
}
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : MoveItemToInventory ( Item * item , const eInventoryType inventory , const uint32_t count , const bool showFlyingLot , bool isModMoveAndEquip , const bool ignoreEquipped , const int32_t preferredSlot ) {
2023-06-28 08:20:41 +00:00
if ( ! item ) return ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
auto * origin = item - > GetInventory ( ) ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
const auto lot = item - > GetLot ( ) ;
2022-01-13 03:48:27 +00:00
2022-12-04 22:25:25 +00:00
const auto subkey = item - > GetSubKey ( ) ;
if ( subkey = = LWOOBJID_EMPTY & & item - > GetConfig ( ) . empty ( ) & & ( ! item - > GetBound ( ) | | ( item - > GetBound ( ) & & item - > GetInfo ( ) . isBOP ) ) ) {
2021-12-05 17:54:36 +00:00
auto left = std : : min < uint32_t > ( count , origin - > GetLotCount ( lot ) ) ;
2022-07-28 13:39:57 +00:00
while ( left > 0 ) {
2023-06-28 08:20:41 +00:00
if ( ! item ) {
2021-12-05 17:54:36 +00:00
item = origin - > FindItemByLot ( lot , false ) ;
2023-06-28 08:20:41 +00:00
if ( ! item ) break ;
2021-12-05 17:54:36 +00:00
}
const auto delta = std : : min < uint32_t > ( item - > GetCount ( ) , left ) ;
left - = delta ;
2023-05-02 22:39:21 +00:00
AddItem ( lot , delta , eLootSourceType : : NONE , inventory , { } , LWOOBJID_EMPTY , showFlyingLot , isModMoveAndEquip , LWOOBJID_EMPTY , origin - > GetType ( ) , 0 , false , preferredSlot ) ;
2021-12-05 17:54:36 +00:00
item - > SetCount ( item - > GetCount ( ) - delta , false , false ) ;
isModMoveAndEquip = false ;
}
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
std : : vector < LDFBaseData * > config ;
2022-07-28 13:39:57 +00:00
for ( auto * const data : item - > GetConfig ( ) ) {
2021-12-05 17:54:36 +00:00
config . push_back ( data - > Copy ( ) ) ;
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
const auto delta = std : : min < uint32_t > ( item - > GetCount ( ) , count ) ;
2023-05-02 22:39:21 +00:00
AddItem ( lot , delta , eLootSourceType : : NONE , inventory , config , LWOOBJID_EMPTY , showFlyingLot , isModMoveAndEquip , subkey , origin - > GetType ( ) , 0 , item - > GetBound ( ) , preferredSlot ) ;
2021-12-05 17:54:36 +00:00
item - > SetCount ( item - > GetCount ( ) - delta , false , false ) ;
}
2023-06-09 09:46:01 +00:00
auto * missionComponent = m_ParentEntity - > GetComponent < MissionComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( missionComponent ) {
2022-07-28 13:39:57 +00:00
if ( IsTransferInventory ( inventory ) ) {
2023-01-22 23:38:47 +00:00
missionComponent - > Progress ( eMissionTaskType : : GATHER , lot , LWOOBJID_EMPTY , " " , - static_cast < int32_t > ( count ) ) ;
2021-12-05 17:54:36 +00:00
}
}
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : MoveStack ( Item * item , const eInventoryType inventory , const uint32_t slot ) {
2023-06-28 08:20:41 +00:00
if ( ! item ) return ;
2022-07-28 13:39:57 +00:00
if ( inventory ! = INVALID & & item - > GetInventory ( ) - > GetType ( ) ! = inventory ) {
2021-12-05 17:54:36 +00:00
auto * newInventory = GetInventory ( inventory ) ;
item - > SetInventory ( newInventory ) ;
}
item - > SetSlot ( slot ) ;
}
2022-07-28 13:39:57 +00:00
Item * InventoryComponent : : FindItemById ( const LWOOBJID id ) const {
2023-06-28 08:20:41 +00:00
if ( id = = LWOOBJID_EMPTY ) {
Game : : logger - > Log ( " InventoryComponent " , " Attempted to find item with empty id! " ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
return nullptr ;
}
for ( const auto [ inventoryType , inventory ] : m_Inventories ) {
auto * item = inventory - > FindItemById ( id ) ;
if ( item ) return item ;
2021-12-05 17:54:36 +00:00
}
return nullptr ;
}
2022-07-28 13:39:57 +00:00
Item * InventoryComponent : : FindItemByLot ( const LOT lot , eInventoryType inventoryType , const bool ignoreEquipped , const bool ignoreBound ) {
if ( inventoryType = = INVALID ) {
2021-12-05 17:54:36 +00:00
inventoryType = Inventory : : FindInventoryTypeForLot ( lot ) ;
}
auto * inventory = GetInventory ( inventoryType ) ;
return inventory - > FindItemByLot ( lot , ignoreEquipped , ignoreBound ) ;
}
2022-07-28 13:39:57 +00:00
Item * InventoryComponent : : FindItemBySubKey ( LWOOBJID id , eInventoryType inventoryType ) {
2023-06-28 08:20:41 +00:00
if ( id = = LWOOBJID_EMPTY ) {
Game : : logger - > Log ( " InventoryComponent " , " Attempted to find item by SubKey with empty id! " ) ;
return nullptr ;
}
2022-07-28 13:39:57 +00:00
if ( inventoryType = = INVALID ) {
2023-06-28 08:20:41 +00:00
for ( const auto & [ inventoryId , inventory ] : m_Inventories ) {
auto * item = inventory - > FindItemBySubKey ( id ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( item ) return item ;
2021-12-05 17:54:36 +00:00
}
return nullptr ;
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
return GetInventory ( inventoryType ) - > FindItemBySubKey ( id ) ;
}
}
2022-07-28 13:39:57 +00:00
bool InventoryComponent : : HasSpaceForLoot ( const std : : unordered_map < LOT , int32_t > & loot ) {
std : : unordered_map < eInventoryType , int32_t > spaceOffset { } ;
2021-12-05 17:54:36 +00:00
uint32_t slotsNeeded = 0 ;
2023-06-28 08:20:41 +00:00
for ( const auto & [ item , count ] : loot ) {
const auto inventoryType = Inventory : : FindInventoryTypeForLot ( item ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( inventoryType = = BRICKS ) continue ;
2021-12-05 17:54:36 +00:00
auto * inventory = GetInventory ( inventoryType ) ;
2023-06-28 08:20:41 +00:00
if ( ! inventory ) return false ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
const auto info = Inventory : : FindItemComponent ( item ) ;
2021-12-05 17:54:36 +00:00
auto stack = static_cast < uint32_t > ( info . stackSize ) ;
2023-06-28 08:20:41 +00:00
auto left = count ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
auto * partial = inventory - > FindItemByLot ( item ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( partial & & partial - > GetCount ( ) < stack ) {
2021-12-05 17:54:36 +00:00
left - = stack - partial - > GetCount ( ) ;
}
auto requiredSlots = std : : ceil ( static_cast < double > ( left ) / stack ) ;
const auto & offsetIter = spaceOffset . find ( inventoryType ) ;
auto freeSpace = inventory - > GetEmptySlots ( ) - ( offsetIter = = spaceOffset . end ( ) ? 0 : offsetIter - > second ) ;
2022-07-28 13:39:57 +00:00
if ( requiredSlots > freeSpace ) {
2021-12-05 17:54:36 +00:00
slotsNeeded + = requiredSlots - freeSpace ;
}
spaceOffset [ inventoryType ] = offsetIter = = spaceOffset . end ( ) ? requiredSlots : offsetIter - > second + requiredSlots ;
}
2022-07-28 13:39:57 +00:00
if ( slotsNeeded > 0 ) {
2023-06-09 09:46:01 +00:00
GameMessages : : SendNotifyNotEnoughInvSpace ( m_ParentEntity - > GetObjectID ( ) , slotsNeeded , ITEMS , m_ParentEntity - > GetSystemAddress ( ) ) ;
2021-12-05 17:54:36 +00:00
return false ;
}
return true ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : LoadXml ( tinyxml2 : : XMLDocument * document ) {
2021-12-05 17:54:36 +00:00
LoadPetXml ( document ) ;
auto * inventoryElement = document - > FirstChildElement ( " obj " ) - > FirstChildElement ( " inv " ) ;
2023-06-28 08:20:41 +00:00
if ( ! inventoryElement ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Failed to find 'inv' xml element! " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
auto * bags = inventoryElement - > FirstChildElement ( " bag " ) ;
2023-06-28 08:20:41 +00:00
if ( ! bags ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Failed to find 'bags' xml element! " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
m_Consumable = inventoryElement - > IntAttribute ( " csl " , LOT_NULL ) ;
auto * bag = bags - > FirstChildElement ( ) ;
2023-06-28 08:20:41 +00:00
while ( bag ) {
2021-12-05 17:54:36 +00:00
unsigned int type ;
unsigned int size ;
bag - > QueryAttribute ( " t " , & type ) ;
bag - > QueryAttribute ( " m " , & size ) ;
auto * inventory = GetInventory ( static_cast < eInventoryType > ( type ) ) ;
inventory - > SetSize ( size ) ;
bag = bag - > NextSiblingElement ( ) ;
}
auto * items = inventoryElement - > FirstChildElement ( " items " ) ;
2023-06-28 08:20:41 +00:00
if ( ! items ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Failed to find 'items' xml element! " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
bag = items - > FirstChildElement ( ) ;
2023-06-28 08:20:41 +00:00
while ( bag ) {
2021-12-05 17:54:36 +00:00
unsigned int type ;
bag - > QueryAttribute ( " t " , & type ) ;
auto * inventory = GetInventory ( static_cast < eInventoryType > ( type ) ) ;
2022-07-28 13:39:57 +00:00
if ( inventory = = nullptr ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Failed to find inventory (%i)! " , type ) ;
2021-12-05 17:54:36 +00:00
return ;
}
auto * itemElement = bag - > FirstChildElement ( ) ;
2023-06-28 08:20:41 +00:00
while ( itemElement ) {
2021-12-05 17:54:36 +00:00
LWOOBJID id ;
LOT lot ;
bool equipped ;
unsigned int slot ;
unsigned int count ;
bool bound ;
LWOOBJID subKey = LWOOBJID_EMPTY ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
itemElement - > QueryAttribute ( " id " , & id ) ;
itemElement - > QueryAttribute ( " l " , & lot ) ;
itemElement - > QueryAttribute ( " eq " , & equipped ) ;
itemElement - > QueryAttribute ( " s " , & slot ) ;
itemElement - > QueryAttribute ( " c " , & count ) ;
itemElement - > QueryAttribute ( " b " , & bound ) ;
itemElement - > QueryAttribute ( " sk " , & subKey ) ;
// Begin custom xml
auto parent = LWOOBJID_EMPTY ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
itemElement - > QueryAttribute ( " parent " , & parent ) ;
// End custom xml
std : : vector < LDFBaseData * > config ;
auto * extraInfo = itemElement - > FirstChildElement ( " x " ) ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
if ( extraInfo ) {
2021-12-05 17:54:36 +00:00
std : : string modInfo = extraInfo - > Attribute ( " ma " ) ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
LDFBaseData * moduleAssembly = new LDFData < std : : u16string > ( u " assemblyPartLOTs " , GeneralUtils : : ASCIIToUTF16 ( modInfo . substr ( 2 , modInfo . size ( ) - 1 ) ) ) ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
config . push_back ( moduleAssembly ) ;
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
const auto * item = new Item ( id , lot , inventory , slot , count , bound , config , parent , subKey ) ;
2022-07-28 13:39:57 +00:00
if ( equipped ) {
2021-12-05 17:54:36 +00:00
const auto info = Inventory : : FindItemComponent ( lot ) ;
2023-06-27 09:01:43 +00:00
UpdateSlot ( info . equipLocation , EquippedItem ( item - > GetId ( ) , item - > GetLot ( ) , item - > GetCount ( ) , item - > GetSlot ( ) ) ) ;
2021-12-05 17:54:36 +00:00
AddItemSkills ( item - > GetLot ( ) ) ;
}
itemElement = itemElement - > NextSiblingElement ( ) ;
}
bag = bag - > NextSiblingElement ( ) ;
}
2023-06-28 08:20:41 +00:00
for ( const auto [ inventoryId , inventory ] : m_Inventories ) {
const auto itemCount = inventory - > GetItems ( ) . size ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( inventory - > GetSize ( ) < itemCount ) {
inventory - > SetSize ( itemCount ) ;
2021-12-05 17:54:36 +00:00
}
}
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : UpdateXml ( tinyxml2 : : XMLDocument * document ) {
2021-12-05 17:54:36 +00:00
UpdatePetXml ( document ) ;
auto * inventoryElement = document - > FirstChildElement ( " obj " ) - > FirstChildElement ( " inv " ) ;
2022-07-28 13:39:57 +00:00
if ( inventoryElement = = nullptr ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Failed to find 'inv' xml element! " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2022-11-28 00:48:46 +00:00
std : : vector < Inventory * > inventoriesToSave ;
2021-12-05 17:54:36 +00:00
2022-11-28 00:48:46 +00:00
// Need to prevent some transfer inventories from being saved
2023-06-28 08:20:41 +00:00
for ( const auto [ inventoryId , inventory ] : this - > m_Inventories ) {
2022-11-28 00:48:46 +00:00
if ( inventory - > GetType ( ) = = VENDOR_BUYBACK | | inventory - > GetType ( ) = = eInventoryType : : MODELS_IN_BBB ) {
2021-12-05 17:54:36 +00:00
continue ;
}
2022-11-28 00:48:46 +00:00
inventoriesToSave . push_back ( inventory ) ;
2021-12-05 17:54:36 +00:00
}
inventoryElement - > SetAttribute ( " csl " , m_Consumable ) ;
auto * bags = inventoryElement - > FirstChildElement ( " bag " ) ;
2023-06-28 08:20:41 +00:00
if ( ! bags ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Failed to find 'bags' xml element! " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
bags - > DeleteChildren ( ) ;
2022-11-28 00:48:46 +00:00
for ( const auto * inventory : inventoriesToSave ) {
2021-12-05 17:54:36 +00:00
auto * bag = document - > NewElement ( " b " ) ;
bag - > SetAttribute ( " t " , inventory - > GetType ( ) ) ;
bag - > SetAttribute ( " m " , static_cast < unsigned int > ( inventory - > GetSize ( ) ) ) ;
bags - > LinkEndChild ( bag ) ;
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
auto * items = inventoryElement - > FirstChildElement ( " items " ) ;
2023-06-28 08:20:41 +00:00
if ( ! items ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " InventoryComponent " , " Failed to find 'items' xml element! " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
items - > DeleteChildren ( ) ;
2022-11-28 00:48:46 +00:00
for ( auto * inventory : inventoriesToSave ) {
2023-06-28 08:20:41 +00:00
if ( inventory - > GetSize ( ) = = 0 ) continue ;
2021-12-05 17:54:36 +00:00
auto * bagElement = document - > NewElement ( " in " ) ;
bagElement - > SetAttribute ( " t " , inventory - > GetType ( ) ) ;
2023-06-28 08:20:41 +00:00
for ( const auto [ itemObjId , item ] : inventory - > GetItems ( ) ) {
2021-12-05 17:54:36 +00:00
auto * itemElement = document - > NewElement ( " i " ) ;
itemElement - > SetAttribute ( " l " , item - > GetLot ( ) ) ;
itemElement - > SetAttribute ( " id " , item - > GetId ( ) ) ;
itemElement - > SetAttribute ( " s " , static_cast < unsigned int > ( item - > GetSlot ( ) ) ) ;
itemElement - > SetAttribute ( " c " , static_cast < unsigned int > ( item - > GetCount ( ) ) ) ;
itemElement - > SetAttribute ( " b " , item - > GetBound ( ) ) ;
itemElement - > SetAttribute ( " eq " , item - > IsEquipped ( ) ) ;
itemElement - > SetAttribute ( " sk " , item - > GetSubKey ( ) ) ;
// Begin custom xml
2023-06-09 08:28:01 +00:00
itemElement - > SetAttribute ( " parent " , item - > GetParentEntity ( ) ) ;
2021-12-05 17:54:36 +00:00
// End custom xml
2022-07-28 13:39:57 +00:00
for ( auto * data : item - > GetConfig ( ) ) {
if ( data - > GetKey ( ) ! = u " assemblyPartLOTs " ) {
2021-12-05 17:54:36 +00:00
continue ;
}
auto * extraInfo = document - > NewElement ( " x " ) ;
extraInfo - > SetAttribute ( " ma " , data - > GetString ( false ) . c_str ( ) ) ;
itemElement - > LinkEndChild ( extraInfo ) ;
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
bagElement - > LinkEndChild ( itemElement ) ;
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
items - > LinkEndChild ( bagElement ) ;
}
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : Serialize ( RakNet : : BitStream * outBitStream , const bool bIsInitialUpdate , unsigned & flags ) {
2023-06-28 08:20:41 +00:00
outBitStream - > Write ( bIsInitialUpdate | | m_Dirty ) ;
2022-07-28 13:39:57 +00:00
if ( bIsInitialUpdate | | m_Dirty ) {
2021-12-05 17:54:36 +00:00
outBitStream - > Write < uint32_t > ( m_Equipped . size ( ) ) ;
2023-06-28 08:20:41 +00:00
for ( const auto [ itemObjId , item ] : m_Equipped ) {
2023-06-27 09:01:43 +00:00
if ( bIsInitialUpdate ) AddItemSkills ( item . lot ) ;
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( item . id ) ;
2022-07-28 13:39:57 +00:00
outBitStream - > Write ( item . lot ) ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
outBitStream - > Write0 ( ) ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
outBitStream - > Write ( item . count > 0 ) ;
if ( item . count > 0 ) outBitStream - > Write ( item . count ) ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
outBitStream - > Write ( item . slot ! = 0 ) ;
if ( item . slot ! = 0 ) outBitStream - > Write < uint16_t > ( item . slot ) ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
outBitStream - > Write0 ( ) ;
2022-01-13 03:48:27 +00:00
2022-05-09 00:57:36 +00:00
bool flag = ! item . config . empty ( ) ;
outBitStream - > Write ( flag ) ;
if ( flag ) {
RakNet : : BitStream ldfStream ;
ldfStream . Write < int32_t > ( item . config . size ( ) ) ; // Key count
for ( LDFBaseData * data : item . config ) {
if ( data - > GetKey ( ) = = u " assemblyPartLOTs " ) {
std : : string newRocketStr = data - > GetValueAsString ( ) + " ; " ;
GeneralUtils : : ReplaceInString ( newRocketStr , " + " , " ; " ) ;
LDFData < std : : u16string > * ldf_data = new LDFData < std : : u16string > ( u " assemblyPartLOTs " , GeneralUtils : : ASCIIToUTF16 ( newRocketStr ) ) ;
ldf_data - > WriteToPacket ( & ldfStream ) ;
delete ldf_data ;
} else {
data - > WriteToPacket ( & ldfStream ) ;
}
}
outBitStream - > Write ( ldfStream . GetNumberOfBytesUsed ( ) + 1 ) ;
outBitStream - > Write < uint8_t > ( 0 ) ; // Don't compress
outBitStream - > Write ( ldfStream ) ;
}
2022-07-25 02:26:51 +00:00
2022-05-25 00:00:52 +00:00
outBitStream - > Write1 ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-28 08:20:41 +00:00
if ( ! bIsInitialUpdate ) m_Dirty = false ;
2021-12-05 17:54:36 +00:00
}
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
outBitStream - > Write0 ( ) ; // Equipped model transforms
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : Update ( float deltaTime ) {
for ( auto * set : m_Itemsets ) {
2021-12-05 17:54:36 +00:00
set - > Update ( deltaTime ) ;
}
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : UpdateSlot ( const std : : string & location , EquippedItem item , bool keepCurrent ) {
2021-12-05 17:54:36 +00:00
const auto index = m_Equipped . find ( location ) ;
2022-07-28 13:39:57 +00:00
if ( index ! = m_Equipped . end ( ) ) {
2021-12-05 17:54:36 +00:00
if ( keepCurrent ) {
m_Equipped . insert_or_assign ( location + std : : to_string ( m_Equipped . size ( ) ) , item ) ;
m_Dirty = true ;
return ;
}
auto * old = FindItemById ( index - > second . id ) ;
2023-06-28 08:20:41 +00:00
if ( old ) {
2021-12-05 17:54:36 +00:00
UnEquipItem ( old ) ;
}
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
m_Equipped . insert_or_assign ( location , item ) ;
m_Dirty = true ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : RemoveSlot ( const std : : string & location ) {
2023-06-28 08:20:41 +00:00
if ( m_Equipped . find ( location ) = = m_Equipped . end ( ) ) return ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
m_Equipped . erase ( location ) ;
m_Dirty = true ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : EquipItem ( Item * item , const bool skipChecks ) {
2022-09-02 18:49:19 +00:00
if ( ! Inventory : : IsValidItem ( item - > GetLot ( ) ) ) return ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
// Temp items should be equippable but other transfer items shouldn't be (for example the instruments in RB)
2021-12-05 17:54:36 +00:00
if ( item - > IsEquipped ( )
2022-07-28 13:39:57 +00:00
| | ( item - > GetInventory ( ) - > GetType ( ) ! = TEMP_ITEMS & & IsTransferInventory ( item - > GetInventory ( ) - > GetType ( ) ) )
| | IsPet ( item - > GetSubKey ( ) ) ) {
2021-12-05 17:54:36 +00:00
return ;
}
2023-06-09 09:46:01 +00:00
auto * character = m_ParentEntity - > GetCharacter ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( character & & ! skipChecks ) {
2021-12-05 17:54:36 +00:00
// Hacky proximity rocket
2023-06-28 08:20:41 +00:00
if ( item - > GetLot ( ) = = LOT_ROCKET ) {
2023-06-08 15:29:17 +00:00
const auto rocketLauchPads = EntityManager : : Instance ( ) - > GetEntitiesByComponent ( eReplicaComponentType : : ROCKET_LAUNCHPAD_CONTROL ) ;
2021-12-05 17:54:36 +00:00
2023-06-09 09:46:01 +00:00
const auto position = m_ParentEntity - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-18 00:20:05 +00:00
for ( auto * launchPad : rocketLauchPads ) {
if ( ! launchPad ) continue ;
auto prereq = launchPad - > GetVarAsString ( u " rocketLaunchPreCondition " ) ;
if ( ! prereq . empty ( ) ) {
PreconditionExpression expression ( prereq ) ;
2023-06-23 15:36:21 +00:00
if ( ! expression . Check ( m_ParentEntity ) ) continue ;
2023-06-18 00:20:05 +00:00
}
if ( Vector3 : : DistanceSquared ( launchPad - > GetPosition ( ) , position ) > 13 * 13 ) continue ;
2021-12-05 17:54:36 +00:00
2023-06-09 09:46:01 +00:00
auto * characterComponent = m_ParentEntity - > GetComponent < CharacterComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( characterComponent ) characterComponent - > SetLastRocketItemID ( item - > GetId ( ) ) ;
2021-12-05 17:54:36 +00:00
2023-06-23 15:36:21 +00:00
launchPad - > OnUse ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
break ;
}
return ;
}
const auto building = character - > GetBuildMode ( ) ;
2023-06-28 08:20:41 +00:00
const auto type = item - > GetInfo ( ) . itemType ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( ! building & & ( item - > GetLot ( ) = = LOT_THINKING_CAP | | type = = eItemType : : LOOT_MODEL | | type = = eItemType : : VEHICLE ) ) return ;
2021-12-05 17:54:36 +00:00
2023-01-22 23:38:47 +00:00
if ( type ! = eItemType : : LOOT_MODEL & & type ! = eItemType : : MODEL ) {
2023-06-09 09:46:01 +00:00
if ( ! item - > GetBound ( ) & & ! item - > GetPreconditionExpression ( ) - > Check ( m_ParentEntity ) ) {
2021-12-05 17:54:36 +00:00
return ;
}
}
}
const auto lot = item - > GetLot ( ) ;
CheckItemSet ( lot ) ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
for ( auto * set : m_Itemsets ) {
2021-12-05 17:54:36 +00:00
set - > OnEquip ( lot ) ;
}
2022-01-13 03:48:27 +00:00
2022-09-02 18:49:19 +00:00
if ( item - > GetInfo ( ) . isBOE ) item - > SetBound ( true ) ;
2021-12-05 17:54:36 +00:00
GenerateProxies ( item ) ;
2022-07-25 02:26:51 +00:00
2023-06-27 09:01:43 +00:00
UpdateSlot ( item - > GetInfo ( ) . equipLocation , EquippedItem ( item - > GetId ( ) , item - > GetLot ( ) , item - > GetCount ( ) , item - > GetSlot ( ) , item - > GetConfig ( ) ) ) ;
2022-01-13 03:48:27 +00:00
2022-03-27 22:24:06 +00:00
ApplyBuff ( item ) ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
AddItemSkills ( item - > GetLot ( ) ) ;
2022-12-21 22:33:41 +00:00
EquipScripts ( item ) ;
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : UnEquipItem ( Item * item ) {
2023-06-28 08:20:41 +00:00
if ( ! item - > IsEquipped ( ) ) return ;
2021-12-05 17:54:36 +00:00
const auto lot = item - > GetLot ( ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
if ( ! Inventory : : IsValidItem ( lot ) ) return ;
2021-12-05 17:54:36 +00:00
CheckItemSet ( lot ) ;
2022-07-28 13:39:57 +00:00
for ( auto * set : m_Itemsets ) {
2021-12-05 17:54:36 +00:00
set - > OnUnEquip ( lot ) ;
}
2022-03-27 22:24:06 +00:00
RemoveBuff ( item ) ;
2022-07-25 02:26:51 +00:00
2021-12-05 17:54:36 +00:00
RemoveItemSkills ( item - > GetLot ( ) ) ;
RemoveSlot ( item - > GetInfo ( ) . equipLocation ) ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
PurgeProxies ( item ) ;
2022-12-21 22:33:41 +00:00
UnequipScripts ( item ) ;
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
// Trigger property event
2022-07-28 13:39:57 +00:00
if ( PropertyManagementComponent : : Instance ( ) ! = nullptr & & item - > GetCount ( ) > 0 & & Inventory : : FindInventoryTypeForLot ( item - > GetLot ( ) ) = = MODELS ) {
2023-06-09 09:46:01 +00:00
PropertyManagementComponent : : Instance ( ) - > GetParentEntity ( ) - > OnZonePropertyModelRemovedWhileEquipped ( m_ParentEntity ) ;
dZoneManager : : Instance ( ) - > GetZoneControlObject ( ) - > OnZonePropertyModelRemovedWhileEquipped ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-12-21 22:33:41 +00:00
2023-06-28 08:20:41 +00:00
void InventoryComponent : : EquipScripts ( Item * equippedItem ) const {
auto * compRegistryTable = CDClientManager : : Instance ( ) . GetTable < CDComponentsRegistryTable > ( ) ;
2023-03-04 07:16:37 +00:00
int32_t scriptComponentID = compRegistryTable - > GetByIDAndType ( equippedItem - > GetLot ( ) , eReplicaComponentType : : SCRIPT , - 1 ) ;
2022-12-21 22:33:41 +00:00
if ( scriptComponentID > - 1 ) {
2023-06-28 08:20:41 +00:00
auto * scriptCompTable = CDClientManager : : Instance ( ) . GetTable < CDScriptComponentTable > ( ) ;
auto scriptCompData = scriptCompTable - > GetByID ( scriptComponentID ) ;
2023-06-09 09:46:01 +00:00
auto * itemScript = CppScripts : : GetScript ( m_ParentEntity , scriptCompData . script_name ) ;
2023-06-28 08:20:41 +00:00
DluAssert ( itemScript ! = nullptr ) ;
2023-06-09 09:46:01 +00:00
itemScript - > OnFactionTriggerItemEquipped ( m_ParentEntity , equippedItem - > GetId ( ) ) ;
2022-12-21 22:33:41 +00:00
}
}
2023-06-28 08:20:41 +00:00
void InventoryComponent : : UnequipScripts ( Item * unequippedItem ) const {
auto * compRegistryTable = CDClientManager : : Instance ( ) . GetTable < CDComponentsRegistryTable > ( ) ;
2023-03-04 07:16:37 +00:00
int32_t scriptComponentID = compRegistryTable - > GetByIDAndType ( unequippedItem - > GetLot ( ) , eReplicaComponentType : : SCRIPT , - 1 ) ;
2022-12-21 22:33:41 +00:00
if ( scriptComponentID > - 1 ) {
2023-06-28 08:20:41 +00:00
auto * scriptCompTable = CDClientManager : : Instance ( ) . GetTable < CDScriptComponentTable > ( ) ;
auto scriptCompData = scriptCompTable - > GetByID ( scriptComponentID ) ;
2023-06-09 09:46:01 +00:00
auto * itemScript = CppScripts : : GetScript ( m_ParentEntity , scriptCompData . script_name ) ;
2023-06-28 08:20:41 +00:00
DluAssert ( itemScript ! = nullptr ) ;
2023-06-09 09:46:01 +00:00
itemScript - > OnFactionTriggerItemUnequipped ( m_ParentEntity , unequippedItem - > GetId ( ) ) ;
2022-12-21 22:33:41 +00:00
}
}
2023-06-28 08:20:41 +00:00
void InventoryComponent : : HandlePossession ( Item * item ) const {
2023-06-09 09:46:01 +00:00
auto * characterComponent = m_ParentEntity - > GetComponent < CharacterComponent > ( ) ;
2022-09-02 18:49:19 +00:00
if ( ! characterComponent ) return ;
2023-06-26 17:36:36 +00:00
auto * possessionComponent = m_ParentEntity - > GetComponent < PossessionComponent > ( ) ;
if ( ! possessionComponent ) return ;
2022-09-02 18:49:19 +00:00
// Don't do anything if we are busy dismounting
2023-06-26 17:36:36 +00:00
if ( possessionComponent - > GetIsDismounting ( ) ) return ;
2022-09-02 18:49:19 +00:00
// Check to see if we are already mounting something
2023-06-26 17:36:36 +00:00
auto * currentlyPossessedEntity = EntityManager : : Instance ( ) - > GetEntity ( possessionComponent - > GetPossessable ( ) ) ;
auto currentlyPossessedItem = possessionComponent - > GetMountItemID ( ) ;
2022-09-02 18:49:19 +00:00
if ( currentlyPossessedItem ) {
2023-06-26 17:36:36 +00:00
if ( currentlyPossessedEntity ) possessionComponent - > Dismount ( currentlyPossessedEntity ) ;
2022-09-02 18:49:19 +00:00
return ;
}
2023-06-09 09:46:01 +00:00
GameMessages : : SendSetStunned ( m_ParentEntity - > GetObjectID ( ) , eStateChangeType : : PUSH , m_ParentEntity - > GetSystemAddress ( ) , LWOOBJID_EMPTY , true , false , true , false , false , false , false , true , true , true , true , true , true , true , true , true ) ;
2022-09-02 18:49:19 +00:00
// Set the mount Item ID so that we know what were handling
2023-06-26 17:36:36 +00:00
possessionComponent - > SetMountItemID ( item - > GetId ( ) ) ;
2023-06-09 09:46:01 +00:00
GameMessages : : SendSetMountInventoryID ( m_ParentEntity , item - > GetId ( ) , UNASSIGNED_SYSTEM_ADDRESS ) ;
2022-09-02 18:49:19 +00:00
// Create entity to mount
2023-06-09 09:46:01 +00:00
auto startRotation = m_ParentEntity - > GetRotation ( ) ;
2022-09-02 18:49:19 +00:00
EntityInfo info { } ;
info . lot = item - > GetLot ( ) ;
2023-06-09 09:46:01 +00:00
info . pos = m_ParentEntity - > GetPosition ( ) ;
2022-09-02 18:49:19 +00:00
info . rot = startRotation ;
2023-06-09 09:46:01 +00:00
info . spawnerID = m_ParentEntity - > GetObjectID ( ) ;
2022-09-02 18:49:19 +00:00
2023-06-09 09:46:01 +00:00
auto * mount = EntityManager : : Instance ( ) - > CreateEntity ( info , nullptr , m_ParentEntity ) ;
2022-09-02 18:49:19 +00:00
// Check to see if the mount is a vehicle, if so, flip it
2023-06-09 08:27:05 +00:00
auto * havokVehiclePhysicsComponent = mount - > GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2023-06-28 08:20:41 +00:00
if ( havokVehiclePhysicsComponent ) characterComponent - > SetIsRacing ( true ) ;
2022-09-02 18:49:19 +00:00
// Setup the destroyable stats
2023-06-09 08:27:05 +00:00
auto * destroyableComponent = mount - > GetComponent < DestroyableComponent > ( ) ;
2023-06-28 08:20:41 +00:00
if ( destroyableComponent ) destroyableComponent - > SetIsImmune ( true ) ;
2022-09-02 18:49:19 +00:00
// Mount it
2023-06-09 08:27:05 +00:00
auto * possessableComponent = mount - > GetComponent < PossessableComponent > ( ) ;
2022-09-02 18:49:19 +00:00
if ( possessableComponent ) {
possessableComponent - > SetIsItemSpawned ( true ) ;
2023-06-09 09:46:01 +00:00
possessableComponent - > SetPossessor ( m_ParentEntity - > GetObjectID ( ) ) ;
2022-09-02 18:49:19 +00:00
// Possess it
2023-06-26 17:36:36 +00:00
possessionComponent - > SetPossessable ( mount - > GetObjectID ( ) ) ;
possessionComponent - > SetPossessableType ( possessableComponent - > GetPossessionType ( ) ) ;
2022-09-02 18:49:19 +00:00
}
2023-06-09 09:46:01 +00:00
GameMessages : : SendSetJetPackMode ( m_ParentEntity , false ) ;
2022-09-02 18:49:19 +00:00
// Make it go to the client
EntityManager : : Instance ( ) - > ConstructEntity ( mount ) ;
// Update the possessor
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2022-09-02 18:49:19 +00:00
// have to unlock the input so it vehicle can be driven
2023-06-09 09:46:01 +00:00
if ( havokVehiclePhysicsComponent ) GameMessages : : SendVehicleUnlockInput ( mount - > GetObjectID ( ) , false , m_ParentEntity - > GetSystemAddress ( ) ) ;
GameMessages : : SendMarkInventoryItemAsActive ( m_ParentEntity - > GetObjectID ( ) , true , eUnequippableActiveType : : MOUNT , item - > GetId ( ) , m_ParentEntity - > GetSystemAddress ( ) ) ;
2022-09-02 18:49:19 +00:00
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : ApplyBuff ( Item * item ) const {
2022-03-27 22:24:06 +00:00
const auto buffs = FindBuffs ( item , true ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
for ( const auto buff : buffs ) {
2023-06-09 09:46:01 +00:00
SkillComponent : : HandleUnmanaged ( buff , m_ParentEntity - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-11-28 00:40:14 +00:00
// TODO Something needs to send the remove buff GameMessage as well when it is unequipping items that would remove buffs.
2022-07-28 13:39:57 +00:00
void InventoryComponent : : RemoveBuff ( Item * item ) const {
2022-03-27 22:24:06 +00:00
const auto buffs = FindBuffs ( item , false ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
for ( const auto buff : buffs ) {
2023-06-09 09:46:01 +00:00
SkillComponent : : HandleUnCast ( buff , m_ParentEntity - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : PushEquippedItems ( ) {
2021-12-05 17:54:36 +00:00
m_Pushed = m_Equipped ;
m_Dirty = true ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : PopEquippedItems ( ) {
2021-12-05 17:54:36 +00:00
auto current = m_Equipped ;
2022-07-28 13:39:57 +00:00
for ( const auto & pair : current ) {
2021-12-05 17:54:36 +00:00
auto * const item = FindItemById ( pair . second . id ) ;
2023-06-28 08:20:41 +00:00
if ( item ) item - > UnEquip ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
for ( const auto & pair : m_Pushed ) {
2021-12-05 17:54:36 +00:00
auto * const item = FindItemById ( pair . second . id ) ;
2023-06-28 08:20:41 +00:00
if ( item ) item - > Equip ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-06 08:30:13 +00:00
m_Pushed . clear ( ) ;
2023-06-09 09:46:01 +00:00
auto * destroyableComponent = m_ParentEntity - > GetComponent < DestroyableComponent > ( ) ;
2022-07-25 02:26:51 +00:00
2022-07-06 08:30:13 +00:00
// Reset stats to full
if ( destroyableComponent ) {
destroyableComponent - > SetHealth ( static_cast < int32_t > ( destroyableComponent - > GetMaxHealth ( ) ) ) ;
destroyableComponent - > SetArmor ( static_cast < int32_t > ( destroyableComponent - > GetMaxArmor ( ) ) ) ;
destroyableComponent - > SetImagination ( static_cast < int32_t > ( destroyableComponent - > GetMaxImagination ( ) ) ) ;
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2022-07-06 08:30:13 +00:00
}
2021-12-05 17:54:36 +00:00
m_Dirty = true ;
}
2022-07-28 13:39:57 +00:00
bool InventoryComponent : : IsEquipped ( const LOT lot ) const {
2023-06-28 08:20:41 +00:00
for ( const auto & [ equipLocation , equippedItem ] : m_Equipped ) {
if ( equippedItem . lot = = lot ) {
2021-12-05 17:54:36 +00:00
return true ;
}
}
return false ;
}
2022-01-07 02:12:47 +00:00
void InventoryComponent : : CheckItemSet ( const LOT lot ) {
2021-12-05 17:54:36 +00:00
// Check if the lot is in the item set cache
2023-06-28 08:20:41 +00:00
if ( std : : find ( m_ItemSetsChecked . begin ( ) , m_ItemSetsChecked . end ( ) , lot ) ! = m_ItemSetsChecked . end ( ) ) return ;
2022-01-13 03:48:27 +00:00
auto query = CDClientDatabase : : CreatePreppedStmt (
2023-06-28 08:20:41 +00:00
" SELECT setID FROM ItemSets WHERE itemIDs LIKE %?%; " ) ;
query . bind ( 1 , lot ) ;
2022-01-13 03:48:27 +00:00
auto result = query . execQuery ( ) ;
2021-12-05 17:54:36 +00:00
2022-01-07 02:12:47 +00:00
while ( ! result . eof ( ) ) {
2021-12-05 17:54:36 +00:00
const auto id = result . getIntField ( 0 ) ;
bool found = false ;
// Check if we have the set already
2022-07-28 13:39:57 +00:00
for ( auto * itemset : m_Itemsets ) {
if ( itemset - > GetID ( ) = = id ) {
2021-12-05 17:54:36 +00:00
found = true ;
break ;
}
}
2022-07-28 13:39:57 +00:00
if ( ! found ) {
2021-12-05 17:54:36 +00:00
auto * set = new ItemSet ( id , this ) ;
m_Itemsets . push_back ( set ) ;
}
result . nextRow ( ) ;
}
m_ItemSetsChecked . push_back ( lot ) ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : AddItemSkills ( const LOT lot ) {
2021-12-05 17:54:36 +00:00
const auto info = Inventory : : FindItemComponent ( lot ) ;
2023-06-28 08:20:41 +00:00
const auto slot = FindBehaviorSlot ( info . itemType ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( slot = = BehaviorSlot : : Invalid ) return ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
const auto index = m_Skills . find ( slot ) ;
const auto skill = FindSkill ( lot ) ;
2023-06-28 08:20:41 +00:00
if ( skill = = 0 ) return ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
if ( index ! = m_Skills . end ( ) ) {
2022-04-09 03:19:27 +00:00
const auto old = index - > second ;
2022-07-25 02:26:51 +00:00
2023-06-09 09:46:01 +00:00
GameMessages : : SendRemoveSkill ( m_ParentEntity , old ) ;
2022-04-09 03:19:27 +00:00
}
2022-07-25 02:26:51 +00:00
2023-06-09 09:46:01 +00:00
GameMessages : : SendAddSkill ( m_ParentEntity , skill , static_cast < int > ( slot ) ) ;
2021-12-05 17:54:36 +00:00
m_Skills . insert_or_assign ( slot , skill ) ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : RemoveItemSkills ( const LOT lot ) {
2021-12-05 17:54:36 +00:00
const auto info = Inventory : : FindItemComponent ( lot ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
const auto slot = FindBehaviorSlot ( info . itemType ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
if ( slot = = BehaviorSlot : : Invalid ) return ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
const auto index = m_Skills . find ( slot ) ;
2023-06-28 08:20:41 +00:00
if ( index = = m_Skills . end ( ) ) return ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
const auto skillId = index - > second ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
GameMessages : : SendRemoveSkill ( m_ParentEntity , skillId ) ;
2021-12-05 17:54:36 +00:00
m_Skills . erase ( slot ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
if ( slot ! = BehaviorSlot : : Primary ) return ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
m_Skills . insert_or_assign ( BehaviorSlot : : Primary , 1 ) ;
GameMessages : : SendAddSkill ( m_ParentEntity , 1 , static_cast < int > ( BehaviorSlot : : Primary ) ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-28 08:20:41 +00:00
void InventoryComponent : : TriggerPassiveAbility ( PassiveAbilityTrigger trigger , Entity * target ) const {
2022-07-28 13:39:57 +00:00
for ( auto * set : m_Itemsets ) {
2022-12-24 02:05:30 +00:00
set - > TriggerPassiveAbility ( trigger , target ) ;
2021-12-05 17:54:36 +00:00
}
}
2023-01-22 23:38:47 +00:00
bool InventoryComponent : : HasAnyPassive ( const std : : vector < eItemSetPassiveAbilityID > & passiveIDs , int32_t equipmentRequirement ) const {
2022-07-28 13:39:57 +00:00
for ( auto * set : m_Itemsets ) {
if ( set - > GetEquippedCount ( ) < equipmentRequirement ) {
2021-12-05 17:54:36 +00:00
continue ;
}
// Check if the set has any of the passive abilities
2023-01-22 23:38:47 +00:00
if ( std : : find ( passiveIDs . begin ( ) , passiveIDs . end ( ) , static_cast < eItemSetPassiveAbilityID > ( set - > GetID ( ) ) ) ! = passiveIDs . end ( ) ) {
2021-12-05 17:54:36 +00:00
return true ;
}
}
return false ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : DespawnPet ( ) {
2023-06-09 09:46:01 +00:00
auto current = PetComponent : : GetActivePet ( m_ParentEntity - > GetObjectID ( ) ) ;
2023-06-28 08:20:41 +00:00
if ( ! current ) return ;
current - > Deactivate ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : SpawnPet ( Item * item ) {
2023-06-09 09:46:01 +00:00
auto current = PetComponent : : GetActivePet ( m_ParentEntity - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( current ) {
2021-12-05 17:54:36 +00:00
current - > Deactivate ( ) ;
2022-07-28 13:39:57 +00:00
if ( current - > GetDatabaseId ( ) = = item - > GetSubKey ( ) ) {
2021-12-05 17:54:36 +00:00
return ;
}
}
2022-06-18 06:53:09 +00:00
// First check if we can summon the pet. You need 1 imagination to do so.
2023-06-09 09:46:01 +00:00
auto * destroyableComponent = m_ParentEntity - > GetComponent < DestroyableComponent > ( ) ;
2022-06-18 06:53:09 +00:00
2022-06-18 20:25:34 +00:00
if ( Game : : config - > GetValue ( " pets_take_imagination " ) = = " 1 " & & destroyableComponent & & destroyableComponent - > GetImagination ( ) < = 0 ) {
2023-06-09 09:46:01 +00:00
GameMessages : : SendUseItemRequirementsResponse ( m_ParentEntity - > GetObjectID ( ) , m_ParentEntity - > GetSystemAddress ( ) , eUseItemResponse : : NoImaginationForPet ) ;
2022-06-18 06:53:09 +00:00
return ;
}
2022-07-28 13:39:57 +00:00
EntityInfo info { } ;
2021-12-05 17:54:36 +00:00
info . lot = item - > GetLot ( ) ;
2023-06-09 09:46:01 +00:00
info . pos = m_ParentEntity - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
info . rot = NiQuaternion : : IDENTITY ;
2023-06-09 09:46:01 +00:00
info . spawnerID = m_ParentEntity - > GetObjectID ( ) ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
auto * pet = EntityManager : : Instance ( ) - > CreateEntity ( info ) ;
2023-06-09 08:27:05 +00:00
auto * petComponent = pet - > GetComponent < PetComponent > ( ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
if ( petComponent ) petComponent - > Activate ( item ) ;
2021-12-05 17:54:36 +00:00
EntityManager : : Instance ( ) - > ConstructEntity ( pet ) ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : SetDatabasePet ( LWOOBJID id , const DatabasePet & data ) {
2021-12-05 17:54:36 +00:00
m_Pets . insert_or_assign ( id , data ) ;
}
2022-07-28 13:39:57 +00:00
const DatabasePet & InventoryComponent : : GetDatabasePet ( LWOOBJID id ) const {
2021-12-05 17:54:36 +00:00
const auto & pair = m_Pets . find ( id ) ;
2023-06-28 08:20:41 +00:00
return pair = = m_Pets . end ( ) ? DATABASE_PET_INVALID : pair - > second ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
BehaviorSlot InventoryComponent : : FindBehaviorSlot ( const eItemType type ) {
2021-12-05 17:54:36 +00:00
switch ( type ) {
2023-01-22 23:38:47 +00:00
case eItemType : : HAT :
2021-12-05 17:54:36 +00:00
return BehaviorSlot : : Head ;
2023-01-22 23:38:47 +00:00
case eItemType : : NECK :
2021-12-05 17:54:36 +00:00
return BehaviorSlot : : Neck ;
2023-01-22 23:38:47 +00:00
case eItemType : : LEFT_HAND :
2021-12-05 17:54:36 +00:00
return BehaviorSlot : : Offhand ;
2023-01-22 23:38:47 +00:00
case eItemType : : RIGHT_HAND :
2021-12-05 17:54:36 +00:00
return BehaviorSlot : : Primary ;
2023-01-22 23:38:47 +00:00
case eItemType : : CONSUMABLE :
2021-12-05 17:54:36 +00:00
return BehaviorSlot : : Consumable ;
default :
return BehaviorSlot : : Invalid ;
}
}
2022-07-28 13:39:57 +00:00
bool InventoryComponent : : IsTransferInventory ( eInventoryType type ) {
2022-11-28 00:48:46 +00:00
return type = = VENDOR_BUYBACK | | type = = VAULT_ITEMS | | type = = VAULT_MODELS | | type = = TEMP_ITEMS | | type = = TEMP_MODELS | | type = = MODELS_IN_BBB ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
uint32_t InventoryComponent : : FindSkill ( const LOT lot ) {
2023-03-17 14:36:21 +00:00
auto * table = CDClientManager : : Instance ( ) . GetTable < CDObjectSkillsTable > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
const auto results = table - > Query ( [ & lot ] ( const CDObjectSkills & entry ) {
return entry . objectTemplate = = static_cast < uint32_t > ( lot ) ;
2022-07-28 13:39:57 +00:00
} ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
for ( const auto & result : results ) {
if ( result . castOnType = = 0 ) {
2021-12-05 17:54:36 +00:00
return result . skillID ;
}
}
return 0 ;
}
2022-07-28 13:39:57 +00:00
std : : vector < uint32_t > InventoryComponent : : FindBuffs ( Item * item , bool castOnEquip ) const {
2022-03-27 22:24:06 +00:00
std : : vector < uint32_t > buffs ;
2023-06-28 08:20:41 +00:00
if ( ! item ) return buffs ;
2023-03-17 14:36:21 +00:00
auto * table = CDClientManager : : Instance ( ) . GetTable < CDObjectSkillsTable > ( ) ;
auto * behaviors = CDClientManager : : Instance ( ) . GetTable < CDSkillBehaviorTable > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
const auto results = table - > Query ( [ item ] ( const CDObjectSkills & entry ) {
2022-03-27 22:24:06 +00:00
return entry . objectTemplate = = static_cast < unsigned int > ( item - > GetLot ( ) ) ;
2022-07-28 13:39:57 +00:00
} ) ;
2021-12-05 17:54:36 +00:00
2023-06-09 09:46:01 +00:00
auto * missions = m_ParentEntity - > GetComponent < MissionComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
for ( const auto & result : results ) {
2023-06-28 08:20:41 +00:00
if ( result . castOnType ! = 1 ) continue ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
const auto entry = behaviors - > GetSkillByID ( result . skillID ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( entry . skillID = = 0 ) {
Game : : logger - > Log ( " InventoryComponent " , " Failed to find buff behavior for skill (%i)! " , result . skillID ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
continue ;
}
2022-07-25 02:26:51 +00:00
2023-06-28 08:20:41 +00:00
if ( missions & & castOnEquip ) {
missions - > Progress ( eMissionTaskType : : USE_SKILL , result . skillID ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-28 08:20:41 +00:00
// If item is not a proxy, add its buff to the added buffs.
if ( item - > GetParentEntity ( ) = = LWOOBJID_EMPTY ) buffs . push_back ( static_cast < uint32_t > ( entry . behaviorID ) ) ;
2021-12-05 17:54:36 +00:00
}
return buffs ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : SetNPCItems ( const std : : vector < LOT > & items ) {
2021-12-05 17:54:36 +00:00
m_Equipped . clear ( ) ;
auto slot = 0u ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
for ( const auto & item : items ) {
2021-12-05 17:54:36 +00:00
const LWOOBJID id = ObjectIDManager : : Instance ( ) - > GenerateObjectID ( ) ;
const auto & info = Inventory : : FindItemComponent ( item ) ;
2022-01-13 03:48:27 +00:00
2023-06-27 09:01:43 +00:00
UpdateSlot ( info . equipLocation , EquippedItem ( id , static_cast < LOT > ( item ) , 1 , slot + + ) , true ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
InventoryComponent : : ~ InventoryComponent ( ) {
2023-06-28 08:20:41 +00:00
for ( const auto & [ inventoryId , inventory ] : m_Inventories ) {
delete inventory ;
2021-12-05 17:54:36 +00:00
}
m_Inventories . clear ( ) ;
2023-06-28 08:20:41 +00:00
std : : for_each ( m_Itemsets . begin ( ) , m_Itemsets . end ( ) , [ ] ( ItemSet * set ) { delete set ; } ) ;
2021-12-05 17:54:36 +00:00
m_Itemsets . clear ( ) ;
m_Pets . clear ( ) ;
}
2022-07-28 13:39:57 +00:00
std : : vector < Item * > InventoryComponent : : GenerateProxies ( Item * parent ) {
2021-12-05 17:54:36 +00:00
std : : vector < Item * > proxies ;
auto subItems = parent - > GetInfo ( ) . subItems ;
2023-06-28 08:20:41 +00:00
if ( subItems . empty ( ) ) return proxies ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
subItems . erase ( std : : remove_if ( subItems . begin ( ) , subItems . end ( ) , : : isspace ) , subItems . end ( ) ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
auto itemsAsStr = GeneralUtils : : SplitString ( subItems , ' , ' ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
std : : vector < int > lots ;
std : : for_each ( itemsAsStr . begin ( ) , itemsAsStr . end ( ) , [ & lots ] ( const std : : string & str ) {
int32_t lot ;
if ( GeneralUtils : : TryParse ( str , lot ) ) lots . push_back ( lot ) ;
else Game : : logger - > Log ( " InventoryComponent " , " failed to parse %s to a lot. " , str . c_str ( ) ) ;
} ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
std : : for_each ( lots . begin ( ) , lots . end ( ) , [ & proxies , parent , this ] ( const int lot ) {
if ( ! Inventory : : IsValidItem ( lot ) ) return ;
2021-12-05 17:54:36 +00:00
auto * inventory = GetInventory ( ITEM_SETS ) ;
auto * proxy = new Item ( lot , inventory , inventory - > FindEmptySlot ( ) , 1 , { } , parent - > GetId ( ) , false ) ;
EquipItem ( proxy ) ;
proxies . push_back ( proxy ) ;
2023-06-28 08:20:41 +00:00
} ) ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
return proxies ;
}
2022-07-28 13:39:57 +00:00
std : : vector < Item * > InventoryComponent : : FindProxies ( const LWOOBJID parent ) {
2021-12-05 17:54:36 +00:00
auto * inventory = GetInventory ( ITEM_SETS ) ;
std : : vector < Item * > proxies ;
2023-06-28 08:20:41 +00:00
for ( const auto & [ itemObjId , item ] : inventory - > GetItems ( ) ) {
if ( item & & item - > GetParentEntity ( ) ! = parent ) proxies . push_back ( item ) ;
2021-12-05 17:54:36 +00:00
}
return proxies ;
}
2022-07-28 13:39:57 +00:00
bool InventoryComponent : : IsValidProxy ( const LWOOBJID parent ) {
2023-06-28 08:20:41 +00:00
for ( const auto & [ inventoryType , inventory ] : m_Inventories ) {
if ( ! inventory ) continue ;
for ( const auto & [ itemObjId , item ] : inventory - > GetItems ( ) ) {
if ( item - > GetId ( ) = = parent ) return true ;
2021-12-05 17:54:36 +00:00
}
}
return false ;
}
2022-07-28 13:39:57 +00:00
bool InventoryComponent : : IsParentValid ( Item * root ) {
2023-06-28 08:20:41 +00:00
if ( root - > GetInfo ( ) . subItems . empty ( ) ) return true ;
2021-12-05 17:54:36 +00:00
const auto id = root - > GetId ( ) ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
for ( const auto & [ inventoryType , inventory ] : m_Inventories ) {
if ( ! inventory ) continue ;
for ( const auto & [ itemObjId , item ] : inventory - > GetItems ( ) ) {
if ( item - > GetParentEntity ( ) = = id ) return true ;
2021-12-05 17:54:36 +00:00
}
}
return false ;
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : CheckProxyIntegrity ( ) {
2021-12-05 17:54:36 +00:00
std : : vector < Item * > dead ;
2022-01-13 03:48:27 +00:00
2023-06-28 08:20:41 +00:00
for ( const auto & [ inventoryType , inventory ] : m_Inventories ) {
if ( ! inventory ) continue ;
for ( const auto & [ itemObjId , item ] : inventory - > GetItems ( ) ) {
2023-06-09 08:28:01 +00:00
const auto parent = item - > GetParentEntity ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-28 08:20:41 +00:00
if ( parent ! = LWOOBJID_EMPTY & & ! IsValidProxy ( parent ) ) dead . push_back ( item ) ;
2021-12-05 17:54:36 +00:00
}
}
2023-06-28 08:20:41 +00:00
std : : for_each ( dead . begin ( ) , dead . end ( ) , [ ] ( Item * item ) { if ( item ) item - > RemoveFromInventory ( ) ; } ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : PurgeProxies ( Item * item ) {
2023-06-09 08:28:01 +00:00
const auto root = item - > GetParentEntity ( ) ;
2022-01-13 03:48:27 +00:00
2022-07-28 13:39:57 +00:00
if ( root ! = LWOOBJID_EMPTY ) {
2021-12-05 17:54:36 +00:00
item = FindItemById ( root ) ;
2023-06-28 08:20:41 +00:00
if ( item ) {
2021-12-05 17:54:36 +00:00
UnEquipItem ( item ) ;
}
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
return ;
}
auto proxies = FindProxies ( item - > GetId ( ) ) ;
2023-06-28 08:20:41 +00:00
std : : for_each ( proxies . begin ( ) , proxies . end ( ) , [ ] ( Item * proxy ) {
if ( ! proxy ) return ;
2021-12-05 17:54:36 +00:00
proxy - > UnEquip ( ) ;
proxy - > RemoveFromInventory ( ) ;
2023-06-28 08:20:41 +00:00
} ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : LoadPetXml ( tinyxml2 : : XMLDocument * document ) {
2021-12-05 17:54:36 +00:00
auto * petInventoryElement = document - > FirstChildElement ( " obj " ) - > FirstChildElement ( " pet " ) ;
2023-06-28 08:20:41 +00:00
if ( ! petInventoryElement ) {
2021-12-05 17:54:36 +00:00
m_Pets . clear ( ) ;
return ;
}
auto * petElement = petInventoryElement - > FirstChildElement ( ) ;
2023-06-28 08:20:41 +00:00
while ( petElement ) {
2021-12-05 17:54:36 +00:00
LWOOBJID id ;
LOT lot ;
int32_t moderationStatus ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
petElement - > QueryAttribute ( " id " , & id ) ;
petElement - > QueryAttribute ( " l " , & lot ) ;
petElement - > QueryAttribute ( " m " , & moderationStatus ) ;
const char * name = petElement - > Attribute ( " n " ) ;
DatabasePet databasePet ;
databasePet . lot = lot ;
databasePet . moderationState = moderationStatus ;
databasePet . name = std : : string ( name ) ;
SetDatabasePet ( id , databasePet ) ;
petElement = petElement - > NextSiblingElement ( ) ;
}
}
2022-07-28 13:39:57 +00:00
void InventoryComponent : : UpdatePetXml ( tinyxml2 : : XMLDocument * document ) {
2021-12-05 17:54:36 +00:00
auto * petInventoryElement = document - > FirstChildElement ( " obj " ) - > FirstChildElement ( " pet " ) ;
2022-07-28 13:39:57 +00:00
if ( petInventoryElement = = nullptr ) {
2021-12-05 17:54:36 +00:00
petInventoryElement = document - > NewElement ( " pet " ) ;
document - > FirstChildElement ( " obj " ) - > LinkEndChild ( petInventoryElement ) ;
}
petInventoryElement - > DeleteChildren ( ) ;
2023-06-28 08:20:41 +00:00
for ( const auto & [ petObjId , pet ] : m_Pets ) {
2021-12-05 17:54:36 +00:00
auto * petElement = document - > NewElement ( " p " ) ;
2023-06-28 08:20:41 +00:00
petElement - > SetAttribute ( " id " , petObjId ) ;
petElement - > SetAttribute ( " l " , pet . lot ) ;
petElement - > SetAttribute ( " m " , pet . moderationState ) ;
petElement - > SetAttribute ( " n " , pet . name . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
petElement - > SetAttribute ( " t " , 0 ) ;
2022-01-13 03:48:27 +00:00
2021-12-05 17:54:36 +00:00
petInventoryElement - > LinkEndChild ( petElement ) ;
}
}