Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2546 lines
75 KiB

  1. //========= Copyright � 1996-2003, Valve LLC, All rights reserved. ============
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "econ_item_inventory.h"
  8. #include "vgui/ILocalize.h"
  9. #include "tier3/tier3.h"
  10. #include "econ_item_system.h"
  11. #include "econ_item.h"
  12. #include "econ_gcmessages.h"
  13. #include "shareddefs.h"
  14. #include "filesystem.h"
  15. #include "econ/econ_coupons.h"
  16. #include "econ/econ_item_view_helpers.h"
  17. #include "cdll_int.h"
  18. #include "cs_econ_item_string_table.h"
  19. #include "econ_game_account_client.h"
  20. #ifdef CLIENT_DLL
  21. #include <igameevents.h>
  22. #include "ienginevgui.h"
  23. #include "clientmode_csnormal.h"
  24. #else
  25. #include "props_shared.h"
  26. #include "basemultiplayerplayer.h"
  27. #endif
  28. #if defined( CSTRIKE15 )
  29. #include "cs_gamerules.h"
  30. #endif
  31. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  32. #include "tf_gcmessages.h"
  33. #include "tf_duel_summary.h"
  34. #include "econ_contribution.h"
  35. #include "tf_player_info.h"
  36. #include "econ/econ_claimcode.h"
  37. #endif
  38. #if defined(TF_DLL) && defined(GAME_DLL)
  39. #include "tf_gc_api.h"
  40. #endif
  41. // memdbgon must be the last include file in a .cpp file!!!
  42. #include "tier0/memdbgon.h"
  43. using namespace GCSDK;
  44. #ifdef _DEBUG
  45. ConVar item_inventory_debug( "item_inventory_debug", "0", FCVAR_REPLICATED | FCVAR_CHEAT );
  46. #endif
  47. #ifdef CLIENT_DLL
  48. extern ConVar econ_debug_loadout_ui;
  49. #endif
  50. #ifdef USE_DYNAMIC_ASSET_LOADING
  51. //extern ConVar item_dynamicload;
  52. #endif
  53. #ifdef _DEBUG
  54. #ifdef CLIENT_DLL
  55. ConVar item_debug_clientacks( "item_debug_clientacks", "0", FCVAR_CLIENTDLL );
  56. #endif
  57. #endif // _DEBUG
  58. // Result codes strings for GC results.
  59. const char* GCResultString[8] =
  60. {
  61. "k_EGCMsgResponseOK", // Request succeeded
  62. "k_EGCMsgResponseDenied", // Request denied
  63. "k_EGCMsgResponseServerError", // Request failed due to a temporary server error
  64. "k_EGCMsgResponseTimeout", // Request timed out
  65. "k_EGCMsgResponseInvalid", // Request was corrupt
  66. "k_EGCMsgResponseNoMatch", // No item definition matched the request
  67. "k_EGCMsgResponseUnknownError", // Request failed with an unknown error
  68. "k_EGCMsgResponseNotLoggedOn", // Client not logged on to steam
  69. };
  70. #ifdef CLIENT_DLL
  71. extern char g_szGeneratingTradingIconPath[ MAX_PATH ];
  72. int g_nGeneratingTradingIconSpew = -1;
  73. void CInventoryItemUpdateManager::Update( float frametime )
  74. {
  75. // Update items that need fixup
  76. {
  77. m_fixupListMutex.Lock();
  78. int32 nTailIdx = m_fixupList.Count() - 1;
  79. if ( nTailIdx >= 0 )
  80. {
  81. CEconItemView &item = *m_fixupList[nTailIdx];
  82. item.FinishLoadCachedInventoryImage( item.m_inventoryImageRgba.Base(), item.m_nNumAsyncReadBytes, item.m_asyncStatus );
  83. m_fixupList.Remove( nTailIdx );
  84. }
  85. m_fixupListMutex.Unlock();
  86. }
  87. int nTail = m_ManagedItems.Count() - 1;
  88. if ( nTail < 0 )
  89. {
  90. g_nGeneratingTradingIconSpew = -1;
  91. return;
  92. }
  93. CEconItemView *pItemView = m_ManagedItems[ nTail ];
  94. if ( g_szGeneratingTradingIconPath[ 0 ] )
  95. {
  96. const CPaintKit *pPaintKit = pItemView->GetCustomPaintKit();
  97. if ( pPaintKit )
  98. {
  99. if ( g_nGeneratingTradingIconSpew == -1 || g_nGeneratingTradingIconSpew > m_ManagedItems.Count() )
  100. {
  101. g_nGeneratingTradingIconSpew = m_ManagedItems.Count();
  102. DevMsg( "Generating icon [%s]%s, %i remaining!\n", pPaintKit->sName.Get(), pItemView->GetItemDefinition()->GetDefinitionName(), m_ManagedItems.Count() );
  103. }
  104. }
  105. }
  106. m_ManagedItems.Remove( nTail );
  107. pItemView->Update();
  108. }
  109. CInventoryItemUpdateManager g_InventoryItemUpdateManager;
  110. #endif // #ifdef CLIENT_DLL
  111. // Inventory Less function.
  112. // Used to sort the inventory items into their positions.
  113. bool CInventoryListLess::Less( CEconItemView* const &src1, CEconItemView *const &src2, void *pCtx )
  114. {
  115. int iPos1 = src1->GetInventoryPosition();
  116. int iPos2 = src2->GetInventoryPosition();
  117. // Context can be specified to point to a func that extracts the position from the backend position.
  118. // Necessary if your inventory packs a bunch of info into the position instead of using it just as a position.
  119. if ( pCtx )
  120. {
  121. CPlayerInventory *pInv = (CPlayerInventory*)pCtx;
  122. iPos1 = pInv->ExtractInventorySortPosition( iPos1 );
  123. iPos2 = pInv->ExtractInventorySortPosition( iPos2 );
  124. }
  125. if ( iPos1 < iPos2 )
  126. return true;
  127. return false;
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Purpose:
  131. //-----------------------------------------------------------------------------
  132. CInventoryManager::CInventoryManager( void )
  133. #ifdef CLIENT_DLL
  134. : m_mapPersonaNamesCache( DefLessFunc( uint32 ) ),
  135. m_mapPredictedFilledSlots( DefLessFunc( uint32 ) )
  136. #endif
  137. {
  138. #ifdef CLIENT_DLL
  139. m_iPredictedDiscards = 0;
  140. m_bIsBatchingPositions = false;
  141. #endif
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose:
  145. //-----------------------------------------------------------------------------
  146. void CInventoryManager::RegisterPlayerInventory( CPlayerInventory *pInventory, IInventoryUpdateListener *pListener /* = NULL */, CSteamID* pSteamID )
  147. {
  148. // If we haven't seen this inventory before, register it
  149. bool bFound = false;
  150. for ( int i = 0; i < m_pInventories.Count(); i++ )
  151. {
  152. if ( m_pInventories[i].pInventory == pInventory )
  153. {
  154. bFound = true;
  155. break;
  156. }
  157. }
  158. if ( !bFound )
  159. {
  160. int iIdx = m_pInventories.AddToTail();
  161. m_pInventories[iIdx].pInventory = pInventory;
  162. m_pInventories[iIdx].pListener = pListener;
  163. if ( pSteamID )
  164. {
  165. SOID_t ownerSOID = GetSOIDFromSteamID( *pSteamID );
  166. pInventory->SetOwner( ownerSOID );
  167. }
  168. if ( pListener )
  169. {
  170. pInventory->AddListener( pListener );
  171. }
  172. }
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. //-----------------------------------------------------------------------------
  177. void CInventoryManager::SteamRequestInventory( CPlayerInventory *pInventory, CSteamID pSteamID, IInventoryUpdateListener *pListener )
  178. {
  179. RegisterPlayerInventory( pInventory, pListener, &pSteamID );
  180. pInventory->RequestInventory( pSteamID );
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Purpose: Called when a gameserver connects to steam.
  184. //-----------------------------------------------------------------------------
  185. void CInventoryManager::GameServerSteamAPIActivated()
  186. {
  187. #if defined(TF_DLL) && defined(GAME_DLL)
  188. GameCoordinator_NotifyGameState();
  189. #endif
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Purpose:
  193. //-----------------------------------------------------------------------------
  194. CPlayerInventory *CInventoryManager::GetInventoryForAccount( uint32 iAccountID )
  195. {
  196. FOR_EACH_VEC( m_pInventories, i )
  197. {
  198. CPlayerInventory* pInventory = m_pInventories[i].pInventory;
  199. if ( GetSteamIDFromSOID( pInventory->GetOwner() ).GetAccountID() == iAccountID )
  200. return m_pInventories[i].pInventory;
  201. }
  202. return NULL;
  203. }
  204. //-----------------------------------------------------------------------------
  205. // Purpose:
  206. //-----------------------------------------------------------------------------
  207. void CInventoryManager::DeregisterInventory( CPlayerInventory *pInventory )
  208. {
  209. int iCount = m_pInventories.Count();
  210. for ( int i = iCount-1; i >= 0; i-- )
  211. {
  212. if ( m_pInventories[i].pInventory == pInventory )
  213. {
  214. m_pInventories.Remove(i);
  215. }
  216. }
  217. }
  218. #ifdef CLIENT_DLL
  219. void CInventoryManager::DestroyPlayerInventoryObject( CPlayerInventory *pPlayerInventory ) const
  220. {
  221. if ( pPlayerInventory )
  222. {
  223. pPlayerInventory->Shutdown();
  224. }
  225. delete pPlayerInventory;
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose:
  229. //-----------------------------------------------------------------------------
  230. void CInventoryManager::UpdateLocalInventory( void )
  231. {
  232. if ( steamapicontext->SteamUser() && GetLocalInventory() )
  233. {
  234. CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
  235. SteamRequestInventory( GetLocalInventory(), steamID );
  236. }
  237. }
  238. #endif
  239. //-----------------------------------------------------------------------------
  240. // Purpose:
  241. //-----------------------------------------------------------------------------
  242. bool CInventoryManager::Init( void )
  243. {
  244. REG_SHARED_OBJECT_SUBCLASS( CEconItem );
  245. REG_SHARED_OBJECT_SUBCLASS( CEconDefaultEquippedDefinitionInstanceClient );
  246. #if defined (CLIENT_DLL)
  247. REG_SHARED_OBJECT_SUBCLASS( CEconGameAccountClient );
  248. REG_SHARED_OBJECT_SUBCLASS( CEconCoupon );
  249. // Make sure the cache directory exists
  250. g_pFullFileSystem->CreateDirHierarchy( ECON_ITEM_GENERATED_ICON_DIR, "DEFAULT_WRITE_PATH" );
  251. #endif
  252. #if defined(GAME_DLL)
  253. REG_SHARED_OBJECT_SUBCLASS( CEconPersonaDataPublic );
  254. #endif
  255. return true;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose:
  259. //-----------------------------------------------------------------------------
  260. void CInventoryManager::PostInit( void )
  261. {
  262. // Initialize the item system.
  263. ItemSystem()->Init();
  264. }
  265. //-----------------------------------------------------------------------------
  266. // Purpose:
  267. //-----------------------------------------------------------------------------
  268. void CInventoryManager::PreInitGC()
  269. {
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Purpose:
  273. //-----------------------------------------------------------------------------
  274. void CInventoryManager::PostInitGC()
  275. {
  276. #ifdef CLIENT_DLL
  277. // The client immediately loads the local player's inventory
  278. UpdateLocalInventory();
  279. #endif
  280. }
  281. //-----------------------------------------------------------------------------
  282. void CInventoryManager::Shutdown()
  283. {
  284. int nInventoryCount = m_pInventories.Count();
  285. for ( int iInventory = 0; iInventory < nInventoryCount; ++iInventory )
  286. {
  287. CPlayerInventory *pInventory = m_pInventories[iInventory].pInventory;
  288. if ( pInventory )
  289. {
  290. pInventory->SOClear();
  291. }
  292. }
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose:
  296. //-----------------------------------------------------------------------------
  297. void CInventoryManager::LevelInitPreEntity()
  298. {
  299. // Throw out any testitem definitions
  300. for ( int i = 0; i < TESTITEM_DEFINITIONS_COUNT; i++ )
  301. {
  302. int iNewDef = TESTITEM_DEFINITIONS_BEGIN_AT + i;
  303. ItemSystem()->GetItemSchema()->ItemTesting_DiscardTestDefinition( iNewDef );
  304. }
  305. // Precache all item models we've got
  306. #ifdef GAME_DLL
  307. CUtlVector<const char *> vecPrecacheStrings;
  308. #endif // GAME_DLL
  309. const CEconItemSchema::ItemDefinitionMap_t& mapItemDefs = ItemSystem()->GetItemSchema()->GetItemDefinitionMap();
  310. FOR_EACH_MAP_FAST( mapItemDefs, i )
  311. {
  312. CEconItemDefinition *pData = mapItemDefs[i];
  313. pData->SetHasBeenLoaded( true );
  314. #ifdef GAME_DLL
  315. bool bDynamicLoad = false;
  316. #ifdef USE_DYNAMIC_ASSET_LOADING
  317. bDynamicLoad = true;//item_dynamicload.GetBool();
  318. #endif // USE_DYNAMIC_ASSET_LOADING
  319. // Robin: Don't precache all assets up front.
  320. bDynamicLoad = true;
  321. pData->GeneratePrecacheModelStrings( bDynamicLoad, &vecPrecacheStrings );
  322. // Precache the models and the gibs for everything the definition requested.
  323. FOR_EACH_VEC( vecPrecacheStrings, i )
  324. {
  325. // Ignore any objects which requested an empty precache string for whatever reason.
  326. if ( vecPrecacheStrings[i] && vecPrecacheStrings[i][0] )
  327. {
  328. int iModelIndex = CBaseEntity::PrecacheModel( vecPrecacheStrings[i] );
  329. PrecacheGibsForModel( iModelIndex );
  330. }
  331. }
  332. vecPrecacheStrings.RemoveAll();
  333. pData->GeneratePrecacheSoundStrings( &vecPrecacheStrings );
  334. // Precache the sounds for everything
  335. FOR_EACH_VEC( vecPrecacheStrings, i )
  336. {
  337. // Ignore any objects which requested an empty precache string for whatever reason.
  338. if ( vecPrecacheStrings[i] && vecPrecacheStrings[i][0] )
  339. {
  340. CBaseEntity::PrecacheScriptSound( vecPrecacheStrings[i] );
  341. }
  342. }
  343. vecPrecacheStrings.RemoveAll();
  344. pData->GeneratePrecacheEffectStrings( &vecPrecacheStrings );
  345. // Precache the sounds for everything
  346. FOR_EACH_VEC( vecPrecacheStrings, i )
  347. {
  348. // Ignore any objects which requested an empty precache string for whatever reason.
  349. if ( vecPrecacheStrings[i] && vecPrecacheStrings[i][0] )
  350. {
  351. PrecacheEffect( vecPrecacheStrings[i] );
  352. }
  353. }
  354. vecPrecacheStrings.RemoveAll();
  355. #endif //#ifdef GAME_DLL
  356. #if defined(CSTRIKE15) && ( defined( CLIENT_DLL ) || defined( GAME_DLL ) )
  357. const char *szSlot = pData->GetRawDefinition()->GetString("item_slot");
  358. if ( szSlot && (
  359. !V_stricmp( szSlot, "secondary" ) ||
  360. !V_stricmp( szSlot, "smg" ) ||
  361. !V_stricmp( szSlot, "heavy" ) ||
  362. !V_stricmp( szSlot, "rifle" )
  363. ) )
  364. {
  365. extern void GenerateWeaponRecoilPatternForItemDefinition( item_definition_index_t idx );
  366. GenerateWeaponRecoilPatternForItemDefinition( pData->GetDefinitionIndex() );
  367. }
  368. #endif
  369. }
  370. // We reset the cached attribute class strings, since it's invalidated by level changes
  371. ItemSystem()->ResetAttribStringCache();
  372. #ifdef GAME_DLL
  373. ItemSystem()->ReloadWhitelist();
  374. #endif
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose:
  378. //-----------------------------------------------------------------------------
  379. void CInventoryManager::LevelShutdownPostEntity()
  380. {
  381. // We reset the cached attribute class strings, since it's invalidated by level changes
  382. ItemSystem()->ResetAttribStringCache();
  383. }
  384. #ifdef CLIENT_DLL
  385. void CInventoryManager::ClearLocalInventoryImages( const CCommand &args )
  386. {
  387. CPlayerInventory *pInventory = GetLocalInventory();
  388. if ( !pInventory )
  389. return;
  390. for ( int i = 0; i < pInventory->GetItemCount(); i++ )
  391. {
  392. CEconItemView *pItem = pInventory->GetItem(i);
  393. if ( pItem )
  394. {
  395. pItem->ClearInventoryImageRgba();
  396. }
  397. }
  398. }
  399. void CInventoryManager::InsertMaterialGenerationJob( CEconItemView *pItemView )
  400. {
  401. g_InventoryItemUpdateManager.AddItemView( pItemView );
  402. }
  403. void CInventoryManager::OnDestroyEconItemView( CEconItemView *pItemView )
  404. {
  405. g_InventoryItemUpdateManager.RemoveItemView( pItemView );
  406. }
  407. #endif
  408. //-----------------------------------------------------------------------------
  409. // Purpose: Lets the client know that we're now connected to the GC
  410. //-----------------------------------------------------------------------------
  411. #ifdef CLIENT_DLL
  412. void CInventoryManager::SendGCConnectedEvent( void )
  413. {
  414. IGameEvent *event = gameeventmanager->CreateEvent( "gc_connected" );
  415. if ( event )
  416. {
  417. gameeventmanager->FireEventClientSide( event );
  418. }
  419. }
  420. #endif
  421. #ifdef CLIENT_DLL
  422. //-----------------------------------------------------------------------------
  423. // Purpose:
  424. //-----------------------------------------------------------------------------
  425. void CInventoryManager::DeleteItem( itemid_t iItemID, bool bRecycle )
  426. {
  427. /** Removed for partner depot **/
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Purpose: Delete any items we can't find static data for. This can happen when we're testing
  431. // internally, and then remove an item. Shouldn't ever happen in the wild.
  432. //-----------------------------------------------------------------------------
  433. int CInventoryManager::DeleteUnknowns( CPlayerInventory *pInventory )
  434. {
  435. // We need to manually walk the main inventory's SOC, because unknown items won't be in the inventory
  436. GCSDK::CGCClientSharedObjectCache *pSOC = pInventory->GetSOC();
  437. if ( pSOC )
  438. {
  439. int iBadItems = 0;
  440. CGCClientSharedObjectTypeCache *pTypeCache = pSOC->FindTypeCache( CEconItem::k_nTypeID );
  441. if( pTypeCache )
  442. {
  443. for( uint32 unItem = 0; unItem < pTypeCache->GetCount(); unItem++ )
  444. {
  445. CEconItem *pItem = (CEconItem *)pTypeCache->GetObject( unItem );
  446. if ( pItem )
  447. {
  448. const CEconItemDefinition *pData = ItemSystem()->GetStaticDataForItemByDefIndex( pItem->GetDefinitionIndex() );
  449. if ( !pData )
  450. {
  451. DeleteItem( pItem->GetItemID() );
  452. iBadItems++;
  453. }
  454. }
  455. }
  456. }
  457. return iBadItems;
  458. }
  459. return 0;
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Purpose: Tries to move the specified item into the player's backpack.
  463. // FAILS if the backpack is full. Returns false in that case.
  464. //-----------------------------------------------------------------------------
  465. bool CInventoryManager::SetItemBackpackPosition( CEconItemView *pItem, uint32 iPosition, bool bForceUnequip, bool bAllowOverflow )
  466. {
  467. CPlayerInventory *pInventory = GetLocalInventory();
  468. if ( !pInventory )
  469. return false;
  470. const int iMaxItems = pInventory->GetMaxItemCount();
  471. if ( !iPosition )
  472. {
  473. // Build a list of empty slots. We track extra slots beyond the backpack for overflow.
  474. CUtlVector< bool > bFilledSlots;
  475. bFilledSlots.SetSize( iMaxItems * 2 );
  476. for ( int i = 0; i < bFilledSlots.Count(); ++i )
  477. {
  478. bFilledSlots[i] = false;
  479. }
  480. for ( int i = 0; i < pInventory->GetItemCount(); i++ )
  481. {
  482. CEconItemView *pTmpItem = pInventory->GetItem(i);
  483. // Ignore the item we're moving.
  484. if ( pTmpItem == pItem )
  485. continue;
  486. int iBackpackPos = GetBackpackPositionFromBackend( pTmpItem->GetInventoryPosition() );
  487. if ( iBackpackPos >= 0 && iBackpackPos < bFilledSlots.Count() )
  488. {
  489. bFilledSlots[iBackpackPos] = true;
  490. }
  491. }
  492. // Add predicted filled slots
  493. for ( int i = m_mapPredictedFilledSlots.FirstInorder(); i != m_mapPredictedFilledSlots.InvalidIndex(); i = m_mapPredictedFilledSlots.NextInorder( i ) )
  494. {
  495. uint32 iBackpackPos = m_mapPredictedFilledSlots.Key( i );
  496. uint64 ullItemID = m_mapPredictedFilledSlots.Element( i );
  497. if ( ullItemID == pItem->GetItemID() )
  498. {
  499. // We already predicted the location of this item.
  500. return !(iBackpackPos > (uint32)iMaxItems);
  501. }
  502. if ( iBackpackPos < (uint32) bFilledSlots.Count() )
  503. {
  504. bFilledSlots[iBackpackPos] = true;
  505. }
  506. }
  507. // Now find an empty slot
  508. for ( int i = 1; i < bFilledSlots.Count(); i++ )
  509. {
  510. if ( !bFilledSlots[i] )
  511. {
  512. iPosition = i;
  513. break;
  514. }
  515. }
  516. if ( !iPosition )
  517. return false;
  518. }
  519. if ( !bAllowOverflow && iPosition > (uint32)iMaxItems )
  520. return false;
  521. //Warning("Moved item %llu to backpack slot: %d\n", pItem->GetItemID(), iPosition );
  522. uint32 iBackendPosition = bForceUnequip ? 0 : pItem->GetInventoryPosition();
  523. SetBackpackPosition( &iBackendPosition, iPosition );
  524. UpdateInventoryPosition( pInventory, pItem->GetItemID(), iBackendPosition );
  525. m_mapPredictedFilledSlots.Insert( iPosition, pItem->GetItemID() );
  526. return true;
  527. }
  528. void CInventoryManager::PredictedBackpackPosFilled( int iBackpackPos )
  529. {
  530. int idx = m_mapPredictedFilledSlots.Find( iBackpackPos );
  531. if ( m_mapPredictedFilledSlots.IsValidIndex( idx ) )
  532. {
  533. m_mapPredictedFilledSlots.Remove( iBackpackPos );
  534. }
  535. }
  536. //-----------------------------------------------------------------------------
  537. // Purpose:
  538. //-----------------------------------------------------------------------------
  539. void CInventoryManager::MoveItemToBackpackPosition( CEconItemView *pItem, int iBackpackPosition )
  540. {
  541. CEconItemView *pOldItem = GetItemByBackpackPosition( iBackpackPosition );
  542. if ( pOldItem )
  543. {
  544. // Move the item in the new spot to our current spot
  545. SetItemBackpackPosition( pOldItem, GetBackpackPositionFromBackend(pItem->GetInventoryPosition()) );
  546. //Warning("Moved OLD item %llu to backpack slot: %d\n", pOldItem->GetItemID(), GetBackpackPositionFromBackend(iBackendPosition) );
  547. }
  548. // Move the item to the new spot
  549. SetItemBackpackPosition( pItem, iBackpackPosition );
  550. //Warning("Moved item %llu to backpack slot: %d\n", pItem->GetItemID(), iBackpackPosition );
  551. }
  552. #ifdef TF_DLL
  553. //-----------------------------------------------------------------------------
  554. // Purpose:
  555. //-----------------------------------------------------------------------------
  556. class CWaitForBackpackSortFinishDialog : public CGenericWaitingDialog
  557. {
  558. public:
  559. CWaitForBackpackSortFinishDialog( vgui::Panel *pParent ) : CGenericWaitingDialog( pParent )
  560. {
  561. }
  562. protected:
  563. virtual void OnTimeout()
  564. {
  565. InventoryManager()->SortBackpackFinished();
  566. }
  567. };
  568. #endif
  569. //-----------------------------------------------------------------------------
  570. // Purpose:
  571. //-----------------------------------------------------------------------------
  572. void CInventoryManager::SortBackpackBy( uint32 iSortType )
  573. {
  574. /** Removed for partner depot **/
  575. }
  576. //-----------------------------------------------------------------------------
  577. // Purpose:
  578. //-----------------------------------------------------------------------------
  579. void CInventoryManager::SortBackpackFinished( void )
  580. {
  581. m_bInBackpackSort = false;
  582. GetLocalInventory()->SendInventoryUpdateEvent();
  583. }
  584. //-----------------------------------------------------------------------------
  585. void CInventoryManager::BeginBackpackPositionTransaction()
  586. {
  587. Assert( !m_bIsBatchingPositions );
  588. m_itemPositions.Clear();
  589. m_bIsBatchingPositions = true;
  590. }
  591. //-----------------------------------------------------------------------------
  592. void CInventoryManager::EndBackpackPositionTransaction()
  593. {
  594. /** Removed for partner depot **/
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Purpose:
  598. //-----------------------------------------------------------------------------
  599. void CInventoryManager::UpdateInventoryPosition( CPlayerInventory *pInventory, uint64 ulItemID, uint32 unNewInventoryPos )
  600. {
  601. /** Removed for partner depot **/
  602. }
  603. //-----------------------------------------------------------------------------
  604. // Purpose:
  605. //-----------------------------------------------------------------------------
  606. void CInventoryManager::UpdateInventoryEquippedState( CPlayerInventory *pInventory, uint64 ulItemID, equipped_class_t unClass, equipped_slot_t unSlot, bool bSwap /*= false*/ )
  607. {
  608. C_EconItemView *pItem = pInventory->GetInventoryItemByItemID( ulItemID );
  609. bool bIsBaseItem = false;
  610. const CEconItemDefinition *pItemDef = NULL;
  611. // The Item isn't in the inventory, test for base item.
  612. if ( !pItem )
  613. {
  614. //Warning("Attempt to update equipped state failure: %s.\n", "could not find matching item ID");
  615. if ( !CombinedItemIdIsDefIndexAndPaint( ulItemID ) )
  616. return;
  617. pItemDef = GetItemSchema()->GetItemDefinition( CombinedItemIdGetDefIndex( ulItemID ) ) ;
  618. if ( !pItemDef )
  619. return;
  620. bIsBaseItem = pItemDef->IsBaseItem();
  621. }
  622. if ( !bIsBaseItem && !pInventory->GetSOCDataForItem( ulItemID ) )
  623. {
  624. //Warning("Attempt to update equipped state failure: %s\n", "could not find SOC data for item");
  625. return;
  626. }
  627. #ifdef CLIENT_DLL
  628. // If this is a set item, other owned items in the set need their descriptions updated
  629. if ( pItem )
  630. {
  631. int nSetIndex = pItem->GetItemSetIndex();
  632. if ( nSetIndex >= 0 )
  633. {
  634. const CEconItemSetDefinition *pItemSetDef = GetItemSchema()->GetItemSetByIndex( nSetIndex );
  635. if ( pItemSetDef && !pItemSetDef->m_bIsCollection )
  636. {
  637. pInventory->MarkSetItemDescriptionsDirty( nSetIndex );
  638. }
  639. }
  640. }
  641. #endif
  642. }
  643. //-----------------------------------------------------------------------------
  644. // Purpose:
  645. //-----------------------------------------------------------------------------
  646. bool CInventoryManager::ShowItemsPickedUp( bool bForce, bool bReturnToGame, bool bNoPanel )
  647. {
  648. /** Removed for partner depot **/
  649. return true;
  650. }
  651. //-----------------------------------------------------------------------------
  652. // Purpose:
  653. //-----------------------------------------------------------------------------
  654. bool CInventoryManager::CheckForRoomAndForceDiscard( void )
  655. {
  656. /** Removed for partner depot **/
  657. return true;
  658. }
  659. //-----------------------------------------------------------------------------
  660. // Purpose:
  661. //-----------------------------------------------------------------------------
  662. CEconItemView *CInventoryManager::GetItemByBackpackPosition( int iBackpackPosition )
  663. {
  664. CPlayerInventory *pInventory = GetLocalInventory();
  665. if ( !pInventory )
  666. return NULL;
  667. // Backpack positions start from 1
  668. if ( iBackpackPosition <= 0 || iBackpackPosition >= pInventory->GetMaxItemCount() )
  669. {
  670. return NULL;
  671. }
  672. for ( int i = 0; i < pInventory->GetItemCount(); i++ )
  673. {
  674. CEconItemView *pItem = pInventory->GetItem(i);
  675. if ( GetBackpackPositionFromBackend( pItem->GetInventoryPosition() ) == iBackpackPosition )
  676. return pItem;
  677. }
  678. return NULL;
  679. }
  680. //-----------------------------------------------------------------------------
  681. // Purpose:
  682. //-----------------------------------------------------------------------------
  683. bool CInventoryManager::HasBeenAckedByClient( CEconItemView *pItem )
  684. {
  685. return ( m_rbItemIdsClientAck.Find( pItem->GetItemID() ) != m_rbItemIdsClientAck.InvalidIndex() );
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Purpose:
  689. //-----------------------------------------------------------------------------
  690. void CInventoryManager::SetAckedByClient( CEconItemView *pItem )
  691. {
  692. m_rbItemIdsClientAck.InsertIfNotFound( pItem->GetItemID() );
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Purpose:
  696. //-----------------------------------------------------------------------------
  697. void CInventoryManager::SetAckedByGC( CEconItemView *pItem, bool bSave )
  698. {
  699. m_rbItemIdsClientAck.Remove( pItem->GetItemID() );
  700. }
  701. bool CInventoryManager::BGetPlayerQuestIdPointsRemaining( uint16 unQuestID, uint32 &numPointsRemaining, uint32 &numPointsUncommitted )
  702. {
  703. /** Removed for partner depot **/
  704. return true;
  705. }
  706. CEconItemView* CInventoryManager::CreateReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 )
  707. {
  708. int iNewItem = m_pTempReferenceItems.AddToTail( new CEconItemView );
  709. CEconItemView *pItemView = m_pTempReferenceItems[ iNewItem ];
  710. pItemView->Init( iDefIndex, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
  711. static CSchemaItemDefHandle hItemDefSticker( "sticker" );
  712. static CSchemaItemDefHandle hItemDefSpray( "spray" );
  713. static CSchemaItemDefHandle hItemDefSprayPaint( "spraypaint" );
  714. static CSchemaItemDefHandle hItemDefQuest( "quest" );
  715. static CSchemaAttributeDefHandle pAttr_QuestID( "quest id" );
  716. static CSchemaItemDefHandle hItemDefMusicKit( "musickit" );
  717. static CSchemaAttributeDefHandle pAttr_MusicID( "music id" );
  718. if ( !pItemView->IsValid() )
  719. return NULL;
  720. if ( iPaintIndex > 0 )
  721. {
  722. if ( ( hItemDefSticker && iDefIndex == hItemDefSticker->GetDefinitionIndex() )
  723. || ( hItemDefSpray && iDefIndex == hItemDefSpray->GetDefinitionIndex() )
  724. || ( hItemDefSprayPaint && iDefIndex == hItemDefSprayPaint->GetDefinitionIndex() ) )
  725. {
  726. float flStickerID = *((float*)&iPaintIndex);
  727. pItemView->SetOrAddAttributeValueByName( "sticker slot 0 id", flStickerID );
  728. if ( ub1 )
  729. {
  730. uint32 ub1_32 = ub1;
  731. float flub1_fl = *( ( float* ) &ub1_32 );
  732. pItemView->SetOrAddAttributeValueByName( "spray tint id", flub1_fl );
  733. }
  734. const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( iDefIndex );
  735. const CStickerKit *pStickerKit = GetItemSchema()->GetStickerKitDefinition( iPaintIndex );
  736. pItemView->SetItemRarityOverride( EconRarity_CombinedItemAndPaintRarity( pItemDef->GetRarity(), pStickerKit->nRarity ) );
  737. }
  738. else if ( hItemDefQuest && pAttr_QuestID && iDefIndex == hItemDefQuest->GetDefinitionIndex() )
  739. {
  740. int iQuestID = iPaintIndex;
  741. if ( iQuestID )
  742. {
  743. uint32 numPointsRemaining = 0;
  744. uint32 numPointsUncommitted = 0;
  745. if ( BGetPlayerQuestIdPointsRemaining( iQuestID, numPointsRemaining, numPointsUncommitted ) && numPointsRemaining )
  746. {
  747. float flPointsRemaining = *( ( float* ) &numPointsRemaining );
  748. pItemView->SetOrAddAttributeValueByName( "quest points remaining", flPointsRemaining );
  749. float flPointsUncommitted = *( ( float* ) &numPointsUncommitted );
  750. pItemView->SetOrAddAttributeValueByName( "operation points", flPointsUncommitted );
  751. }
  752. float flQuestID = *( ( float* )&iQuestID );
  753. pItemView->SetOrAddAttributeValueByName( "quest id", flQuestID );
  754. }
  755. pItemView->SetItemRarityOverride( 1 ); // TODO: different missions rarity?
  756. }
  757. else if ( hItemDefMusicKit && pAttr_MusicID && iDefIndex == hItemDefMusicKit->GetDefinitionIndex() )
  758. {
  759. if ( iPaintIndex )
  760. {
  761. float flMusicID = *( ( float* )&iPaintIndex );
  762. pItemView->SetOrAddAttributeValueByName( "music id", flMusicID );
  763. if ( ub1 )
  764. { // This is how StatTrak Music Kits are made
  765. Assert( ub1 == AE_STRANGE );
  766. pItemView->SetItemQualityOverride( ub1 );
  767. }
  768. }
  769. }
  770. else
  771. {
  772. pItemView->SetOrAddAttributeValueByName( "set item texture prefab", iPaintIndex );
  773. const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( iDefIndex );
  774. AssertMsg1( pItemDef, "Failed to get item definition for index: %i\n", iDefIndex );
  775. if ( !pItemDef )
  776. return NULL;
  777. const CPaintKit *pPaintKit = GetItemSchema()->GetPaintKitDefinition( iPaintIndex );
  778. AssertMsg1( pPaintKit, "Failed to get paintkit definition for index: %i\n", iPaintIndex );
  779. if ( !pPaintKit )
  780. return NULL;
  781. pItemView->SetItemRarityOverride( EconRarity_CombinedItemAndPaintRarity( pItemDef->GetRarity(), pPaintKit->nRarity ) );
  782. }
  783. #ifdef CLIENT_DLL
  784. InsertMaterialGenerationJob( pItemView );
  785. #endif // #ifdef CLIENT_DLL
  786. }
  787. else
  788. {
  789. if ( pItemView->GetItemDefinition() && !pItemView->GetItemDefinition()->IsBaseItem() )
  790. {
  791. pItemView->SetItemRarityOverride( pItemView->GetItemDefinition()->GetRarity() );
  792. // Genuine collectibles will force the item quality
  793. uint8 unDefinitionQuality = pItemView->GetItemDefinition()->GetQuality();
  794. if ( unDefinitionQuality == AE_GENUINE )
  795. {
  796. pItemView->SetItemQualityOverride( unDefinitionQuality );
  797. }
  798. }
  799. else
  800. {
  801. pItemView->SetItemRarityOverride( 0 /* default aka stock */ );
  802. }
  803. }
  804. return pItemView;
  805. }
  806. void CInventoryManager::RemoveReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 )
  807. {
  808. static CSchemaItemDefHandle hItemDefSticker( "sticker" );
  809. static CSchemaItemDefHandle hItemDefSpray( "spray" );
  810. static CSchemaItemDefHandle hItemDefSprayPaint( "spraypaint" );
  811. static CSchemaAttributeDefHandle pAttr_SprayTintID( "spray tint id" );
  812. static CSchemaItemDefHandle hItemDefQuest( "quest" );
  813. static CSchemaAttributeDefHandle pAttr_QuestID( "quest id" );
  814. static CSchemaItemDefHandle hItemDefMusicKit( "musickit" );
  815. static CSchemaAttributeDefHandle pAttr_MusicID( "music id" );
  816. static CSchemaItemDefHandle hItemDefWearable( "wearable" );
  817. FOR_EACH_VEC( m_pTempReferenceItems, i )
  818. {
  819. CEconItemView *pItem = m_pTempReferenceItems[ i ];
  820. if ( pItem->GetItemIndex() == iDefIndex )
  821. {
  822. if ( ( hItemDefSticker && iDefIndex == hItemDefSticker->GetDefinitionIndex() )
  823. || ( hItemDefSpray && iDefIndex == hItemDefSpray->GetDefinitionIndex() )
  824. || ( hItemDefSprayPaint && iDefIndex == hItemDefSprayPaint->GetDefinitionIndex() ) )
  825. {
  826. uint32 unTintID = 0;
  827. if ( ( pItem->GetStickerAttributeBySlotIndexInt( 0, k_EStickerAttribute_ID, 0 ) == uint32( iPaintIndex ) ) &&
  828. pAttr_SprayTintID && ( pItem->FindAttribute( pAttr_SprayTintID, &unTintID ), ( unTintID == ub1 ) )
  829. )
  830. {
  831. m_pTempReferenceItems.Remove( i );
  832. return;
  833. }
  834. }
  835. else if ( hItemDefQuest && pAttr_QuestID && iDefIndex == hItemDefQuest->GetDefinitionIndex() )
  836. {
  837. uint32 unQuestID = 0;
  838. if ( pItem->FindAttribute( pAttr_QuestID, &unQuestID ) && ( unQuestID == uint32( iPaintIndex ) ) )
  839. {
  840. m_pTempReferenceItems.Remove( i );
  841. return;
  842. }
  843. }
  844. else if ( hItemDefMusicKit && pAttr_MusicID && iDefIndex == hItemDefMusicKit->GetDefinitionIndex() )
  845. {
  846. uint32 unMusicID = 0;
  847. if ( pItem->FindAttribute( pAttr_MusicID, &unMusicID ) && ( unMusicID == uint32( iPaintIndex ) ) )
  848. { // Music Kits can be regular or StatTrak
  849. int iQualityNeeded = ub1 ? ub1 : AE_UNIQUE;
  850. if ( iQualityNeeded == pItem->GetQuality() )
  851. {
  852. m_pTempReferenceItems.Remove( i );
  853. return;
  854. }
  855. }
  856. }
  857. else // code is currently valid for both wearables and weapons with paint kits
  858. {
  859. if ( pItem->GetCustomPaintKitIndex() == iPaintIndex )
  860. {
  861. m_pTempReferenceItems.Remove( i );
  862. return;
  863. }
  864. }
  865. }
  866. }
  867. }
  868. CEconItemView* CInventoryManager::FindReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 )
  869. {
  870. static CSchemaItemDefHandle hItemDefSticker( "sticker" );
  871. static CSchemaItemDefHandle hItemDefSpray( "spray" );
  872. static CSchemaItemDefHandle hItemDefSprayPaint( "spraypaint" );
  873. static CSchemaAttributeDefHandle pAttr_SprayTintID( "spray tint id" );
  874. static CSchemaItemDefHandle hItemDefQuest( "quest" );
  875. static CSchemaAttributeDefHandle pAttr_QuestID( "quest id" );
  876. static CSchemaItemDefHandle hItemDefMusicKit( "musickit" );
  877. static CSchemaAttributeDefHandle pAttr_MusicID( "music id" );
  878. FOR_EACH_VEC( m_pTempReferenceItems, i )
  879. {
  880. CEconItemView *pItem = m_pTempReferenceItems[ i ];
  881. if ( pItem->GetItemIndex() == iDefIndex )
  882. {
  883. if ( ( hItemDefSticker && iDefIndex == hItemDefSticker->GetDefinitionIndex() )
  884. || ( hItemDefSpray && iDefIndex == hItemDefSpray->GetDefinitionIndex() )
  885. || ( hItemDefSprayPaint && iDefIndex == hItemDefSprayPaint->GetDefinitionIndex() ) )
  886. {
  887. uint32 unTintID = 0;
  888. if ( ( pItem->GetStickerAttributeBySlotIndexInt( 0, k_EStickerAttribute_ID, 0 ) == uint32( iPaintIndex ) ) &&
  889. pAttr_SprayTintID && ( pItem->FindAttribute( pAttr_SprayTintID, &unTintID ), ( unTintID == ub1 ) )
  890. )
  891. {
  892. return pItem;
  893. }
  894. }
  895. else if ( hItemDefQuest && pAttr_QuestID && iDefIndex == hItemDefQuest->GetDefinitionIndex() )
  896. {
  897. uint32 unQuestID = 0;
  898. if ( pItem->FindAttribute( pAttr_QuestID, &unQuestID ) && ( unQuestID == uint32( iPaintIndex ) ) )
  899. {
  900. // Ensure that the points remaining attribute is correct, just always stomp it
  901. uint32 numPointsRemaining = 0;
  902. uint32 numPointsUncommitted = 0;
  903. if ( BGetPlayerQuestIdPointsRemaining( unQuestID, numPointsRemaining, numPointsUncommitted ) && numPointsRemaining )
  904. {
  905. float flPointsRemaining = *( ( float* ) &numPointsRemaining );
  906. pItem->SetOrAddAttributeValueByName( "quest points remaining", flPointsRemaining );
  907. float flPointsUncommitted = *( ( float* ) &numPointsUncommitted );
  908. pItem->SetOrAddAttributeValueByName( "operation points", flPointsUncommitted );
  909. }
  910. return pItem;
  911. }
  912. }
  913. else if ( hItemDefMusicKit && pAttr_MusicID && iDefIndex == hItemDefMusicKit->GetDefinitionIndex() )
  914. {
  915. uint32 unMusicID = 0;
  916. if ( pItem->FindAttribute( pAttr_MusicID, &unMusicID ) && ( unMusicID == uint32( iPaintIndex ) ) )
  917. { // Music Kits can be regular or StatTrak
  918. int iQualityNeeded = ub1 ? ub1 : AE_UNIQUE;
  919. if ( iQualityNeeded == pItem->GetQuality() )
  920. return pItem;
  921. }
  922. }
  923. else // code is currently valid for both wearables and weapons with paint kits
  924. {
  925. if ( pItem->GetCustomPaintKitIndex() == iPaintIndex )
  926. {
  927. return pItem;
  928. }
  929. }
  930. }
  931. }
  932. return NULL;
  933. }
  934. CEconItemView* CInventoryManager::FindOrCreateReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 )
  935. {
  936. CEconItemView *pItem = FindReferenceEconItem( iDefIndex, iPaintIndex, ub1 );
  937. if ( !pItem )
  938. {
  939. pItem = CreateReferenceEconItem( iDefIndex, iPaintIndex, ub1 );
  940. }
  941. return pItem;
  942. }
  943. CEconItemView* CInventoryManager::FindOrCreateReferenceEconItem( itemid_t ullFauxItemId )
  944. {
  945. if ( !CombinedItemIdIsDefIndexAndPaint( ullFauxItemId) )
  946. {
  947. Assert(0);
  948. return NULL;
  949. }
  950. item_definition_index_t nDefIndex = CombinedItemIdGetDefIndex( ullFauxItemId );
  951. uint16 nPaintIndex = CombinedItemIdGetPaint( ullFauxItemId );
  952. uint8 ub1 = CombinedItemIdGetUB1( ullFauxItemId );
  953. return FindOrCreateReferenceEconItem( nDefIndex, nPaintIndex, ub1 );
  954. }
  955. #endif // CLIENT_DLL
  956. //=======================================================================================================================
  957. // PLAYER INVENTORY
  958. //=======================================================================================================================
  959. //-----------------------------------------------------------------------------
  960. // Purpose:
  961. //-----------------------------------------------------------------------------
  962. CPlayerInventory::CPlayerInventory( void )
  963. {
  964. m_bGotItemsFromSteamAtLeastOnce = false;
  965. m_bCurrentlySubscribedToSteam = false;
  966. m_pSOCache = NULL;
  967. m_nTargetRecipe = -1;
  968. }
  969. //-----------------------------------------------------------------------------
  970. // Purpose:
  971. //-----------------------------------------------------------------------------
  972. CPlayerInventory::~CPlayerInventory()
  973. {
  974. }
  975. void CPlayerInventory::Shutdown()
  976. {
  977. SOClear();
  978. InventoryManager()->DeregisterInventory( this );
  979. }
  980. //-----------------------------------------------------------------------------
  981. // Purpose:
  982. //-----------------------------------------------------------------------------
  983. void CPlayerInventory::SOClear()
  984. {
  985. // Somebody registered as a listener through us, but now our Steam ID
  986. // is changing? This is bad news.
  987. Assert( m_vecListeners.Count() == 0 );
  988. while ( m_vecListeners.Count() > 0 )
  989. {
  990. RemoveListener( m_vecListeners[0] );
  991. }
  992. // If we were subscribed, we should have gotten our unsubscribe message,
  993. // and that should have cleared the pointer
  994. // [ when we unsubscribe we no longer remove all references, so the assert is no longer valid ]
  995. // Assert( m_pSOCache == NULL);
  996. m_pSOCache = NULL;
  997. m_Items.Purge();
  998. m_aDefaultEquippedDefinitionItems.PurgeAndDeleteElements();
  999. }
  1000. //-----------------------------------------------------------------------------
  1001. // Purpose:
  1002. //-----------------------------------------------------------------------------
  1003. void CPlayerInventory::RequestInventory( SOID_t ID )
  1004. {
  1005. // Make sure we don't already have somebody else's stuff
  1006. // on hand
  1007. if ( m_OwnerID != ID )
  1008. SOClear();
  1009. // Remember whose inventory we're looking at
  1010. m_OwnerID = ID;
  1011. }
  1012. void CPlayerInventory::AddListener( GCSDK::ISharedObjectListener *pListener )
  1013. {
  1014. Assert( m_OwnerID.IsValid() );
  1015. if ( m_vecListeners.Find( pListener ) >= 0 )
  1016. {
  1017. Assert( !"CPlayerInventory::AddListener - added multiple times" );
  1018. }
  1019. else
  1020. {
  1021. m_vecListeners.AddToTail( pListener );
  1022. }
  1023. }
  1024. void CPlayerInventory::RemoveListener( GCSDK::ISharedObjectListener *pListener )
  1025. {
  1026. if ( m_OwnerID.IsValid() )
  1027. {
  1028. m_vecListeners.FindAndFastRemove( pListener );
  1029. }
  1030. else
  1031. {
  1032. Assert( m_vecListeners.Count() == 0 );
  1033. }
  1034. }
  1035. //-----------------------------------------------------------------------------
  1036. // Purpose: Helper function to add a new item for a econ item
  1037. //-----------------------------------------------------------------------------
  1038. bool CPlayerInventory::AddEconItem( CEconItem * pItem, bool bUpdateAckFile, bool bWriteAckFile, bool bCheckForNewItems )
  1039. {
  1040. CEconItemView *pNewItem = new CEconItemView;
  1041. if( !FilloutItemFromEconItem( pNewItem, pItem ) )
  1042. {
  1043. return false;
  1044. }
  1045. #ifndef CLIENT_DLL
  1046. CEconItemView::s_mapLookupByID.InsertOrReplace( pItem->GetItemID(),
  1047. CombinedItemIdMakeFromDefIndexAndPaint(
  1048. pItem->GetDefinitionIndex(), pItem->GetCustomPaintKitIndex() )
  1049. );
  1050. // Also insert the fact that this account owns an item of this defindex
  1051. CEconItemView::s_mapLookupByID.InsertOrReplace(
  1052. (1ull << 63)
  1053. | ( uint64( GetSteamIDFromSOID( GetOwner() ).GetAccountID() & 0x7FFFFFFF ) << 32 )
  1054. | pItem->GetDefinitionIndex(),
  1055. 0ull
  1056. );
  1057. #endif
  1058. m_Items.Add( pNewItem );
  1059. ItemHasBeenUpdated( pNewItem, bUpdateAckFile, bWriteAckFile, k_EInventoryItemCreated );
  1060. int nItemSet = pItem->GetItemSetIndex();
  1061. if ( nItemSet )
  1062. {
  1063. const CEconItemSetDefinition *pItemSetDef = GetItemSchema()->GetItemSetByIndex( nItemSet );
  1064. if ( pItemSetDef && pItemSetDef->m_bIsCollection )
  1065. {
  1066. MarkSetItemDescriptionsDirty( nItemSet );
  1067. }
  1068. }
  1069. #ifdef CLIENT_DLL
  1070. if ( bCheckForNewItems && InventoryManager()->GetLocalInventory() == this )
  1071. {
  1072. bool bNotify = IsUnacknowledged( pItem->GetInventoryToken() );
  1073. // ignore Halloween drops
  1074. bNotify &= pItem->GetOrigin() != kEconItemOrigin_HalloweenDrop;
  1075. // only notify for specific reasons
  1076. unacknowledged_item_inventory_positions_t reason = GetUnacknowledgedReason( pItem->GetInventoryToken() );
  1077. bNotify &=
  1078. reason == UNACK_ITEM_DROPPED || reason == UNACK_ITEM_SUPPORT ||
  1079. reason == UNACK_ITEM_EARNED || reason == UNACK_ITEM_REFUNDED ||
  1080. reason == UNACK_ITEM_COLLECTION_REWARD || reason == UNACK_ITEM_TRADED ||
  1081. reason == UNACK_ITEM_RECYCLING || reason == UNACK_ITEM_PURCHASED;
  1082. if ( bNotify )
  1083. {
  1084. OnHasNewItems();
  1085. }
  1086. }
  1087. #endif
  1088. return true;
  1089. }
  1090. bool CPlayerInventory::AddEconDefaultEquippedDefinition( CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinition )
  1091. {
  1092. int nItemDef = pDefaultEquippedDefinition->Obj().item_definition();
  1093. int nClassID = pDefaultEquippedDefinition->Obj().class_id();
  1094. int nSlotID = pDefaultEquippedDefinition->Obj().slot_id();
  1095. SetDefaultEquippedDefinitionItemBySlot( nClassID, nSlotID, nItemDef );
  1096. return true;
  1097. }
  1098. //-----------------------------------------------------------------------------
  1099. // Purpose: Creates a script item and associates it with this econ item
  1100. //-----------------------------------------------------------------------------
  1101. void CPlayerInventory::SOCreated( SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent )
  1102. {
  1103. #ifdef _DEBUG
  1104. Msg("CPlayerInventory::SOCreated %s [event = %u]\n", CSteamID( owner.ID() ).Render(), eEvent );
  1105. #endif
  1106. if ( owner != m_OwnerID )
  1107. return;
  1108. // We shouldn't get these notifications unless we're subscribed, right?
  1109. if ( m_pSOCache == NULL)
  1110. {
  1111. Assert( m_pSOCache );
  1112. return;
  1113. }
  1114. // Don't bother unless it's an incremental notification.
  1115. // For mass updates, we'll do everything more efficiently in one place
  1116. if ( eEvent != GCSDK::eSOCacheEvent_Incremental )
  1117. {
  1118. Assert( eEvent == GCSDK::eSOCacheEvent_Subscribed || eEvent == GCSDK::eSOCacheEvent_Resubscribed || eEvent == GCSDK::eSOCacheEvent_ListenerAdded );
  1119. return;
  1120. }
  1121. if ( pObject->GetTypeID() == CEconItem::k_nTypeID )
  1122. {
  1123. CEconItem *pItem = (CEconItem *)pObject;
  1124. AddEconItem( pItem, true, true, true );
  1125. }
  1126. else if ( pObject->GetTypeID() == CEconDefaultEquippedDefinitionInstanceClient::k_nTypeID )
  1127. {
  1128. CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinitionInstance = (CEconDefaultEquippedDefinitionInstanceClient *)pObject;
  1129. AddEconDefaultEquippedDefinition( pDefaultEquippedDefinitionInstance );
  1130. }
  1131. else
  1132. {
  1133. return;
  1134. }
  1135. SendInventoryUpdateEvent();
  1136. }
  1137. //-----------------------------------------------------------------------------
  1138. // Purpose: Updates the script item associated with this econ item
  1139. //-----------------------------------------------------------------------------
  1140. void CPlayerInventory::SOUpdated( SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent )
  1141. {
  1142. #ifdef _DEBUG
  1143. {
  1144. CSteamID steamIDOwner( owner.ID() );
  1145. static CSteamID spewSteamID;
  1146. static GCSDK::ESOCacheEvent spewEvent;
  1147. static double spewTime = 0;
  1148. if ( spewSteamID.IsValid() && spewSteamID == steamIDOwner && spewEvent == eEvent && Plat_FloatTime() - spewTime < 3.0f )
  1149. {
  1150. ; // same event
  1151. }
  1152. else
  1153. {
  1154. spewSteamID = steamIDOwner;
  1155. spewEvent = eEvent;
  1156. spewTime = Plat_FloatTime();
  1157. Msg("CPlayerInventory::SOUpdated %s [event = %u]\n", steamIDOwner.Render(), eEvent );
  1158. }
  1159. }
  1160. #endif
  1161. if ( owner != m_OwnerID )
  1162. return;
  1163. // We shouldn't get these notifications unless we're subscribed, right?
  1164. if ( m_pSOCache == NULL)
  1165. {
  1166. Assert( m_pSOCache );
  1167. return;
  1168. }
  1169. // Don't bother unless it's an incremental notification.
  1170. // For mass updates, we'll do everything more efficiently in one place
  1171. if ( eEvent != GCSDK::eSOCacheEvent_Incremental )
  1172. {
  1173. Assert( eEvent == GCSDK::eSOCacheEvent_Subscribed || eEvent == GCSDK::eSOCacheEvent_Resubscribed );
  1174. return;
  1175. }
  1176. bool bChanged = false;
  1177. switch ( pObject->GetTypeID() )
  1178. {
  1179. case CEconItem::k_nTypeID:
  1180. {
  1181. CEconItem *pEconItem = (CEconItem *)pObject;
  1182. CEconItemView *pScriptItem = GetInventoryItemByItemID( pEconItem->GetItemID() );
  1183. if ( pScriptItem )
  1184. {
  1185. if ( FilloutItemFromEconItem( pScriptItem, pEconItem ) )
  1186. {
  1187. ItemHasBeenUpdated( pScriptItem, false, false, k_EInventoryItemUpdated );
  1188. }
  1189. bChanged = true;
  1190. }
  1191. else
  1192. {
  1193. // The item isn't in this inventory right now. But it may need to be
  1194. // after the update, so try adding it and see if the inventory wants it.
  1195. bChanged = AddEconItem( pEconItem, false, false, false );
  1196. }
  1197. }
  1198. break;
  1199. case CEconDefaultEquippedDefinitionInstanceClient::k_nTypeID:
  1200. {
  1201. CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinitionInstance = (CEconDefaultEquippedDefinitionInstanceClient *)pObject;
  1202. SetDefaultEquippedDefinitionItemBySlot( pDefaultEquippedDefinitionInstance->Obj().class_id(),
  1203. pDefaultEquippedDefinitionInstance->Obj().slot_id(),
  1204. pDefaultEquippedDefinitionInstance->Obj().item_definition() );
  1205. DefaultEquippedDefinitionHasBeenUpdated( pDefaultEquippedDefinitionInstance );
  1206. #ifdef CLIENT_DLL
  1207. if ( econ_debug_loadout_ui.GetBool() )
  1208. {
  1209. const CEconItemDefinition *pDef = GetItemSchema()->GetItemDefinition( pDefaultEquippedDefinitionInstance->Obj().item_definition() );
  1210. if ( pDef )
  1211. {
  1212. ConColorMsg( Color( 205, 0, 205, 255 ), "LOADOUT GC UPDATE BaseItem \"%s\" to slot: %i\n", pDef->GetDefinitionName(), pDefaultEquippedDefinitionInstance->Obj().slot_id() );
  1213. }
  1214. }
  1215. #endif
  1216. #ifdef GAME_DLL
  1217. bChanged = true;
  1218. #endif
  1219. }
  1220. break;
  1221. case CEconPersonaDataPublic::k_nTypeID:
  1222. {
  1223. #ifdef GAME_DLL
  1224. bChanged = true;
  1225. #endif
  1226. }
  1227. break;
  1228. }
  1229. if ( bChanged )
  1230. {
  1231. #ifdef CLIENT_DLL
  1232. // Client doesn't update inventory while items are moving in a backpack sort. Does it once at the sort end instead.
  1233. if ( !InventoryManager()->IsInBackpackSort() )
  1234. #endif
  1235. {
  1236. SendInventoryUpdateEvent();
  1237. }
  1238. #ifdef _DEBUG
  1239. if ( item_inventory_debug.GetBool() )
  1240. {
  1241. DumpInventoryToConsole( true );
  1242. }
  1243. #endif
  1244. }
  1245. }
  1246. //-----------------------------------------------------------------------------
  1247. // Purpose: Removes the script item associated with this econ item
  1248. //-----------------------------------------------------------------------------
  1249. void CPlayerInventory::SODestroyed( SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent )
  1250. {
  1251. #ifdef _DEBUG
  1252. Msg("CPlayerInventory::SODestroyed %s [event = %u]\n", CSteamID( owner.ID() ).Render(), eEvent );
  1253. #endif
  1254. if( pObject->GetTypeID() != CEconItem::k_nTypeID )
  1255. return;
  1256. if ( owner != m_OwnerID )
  1257. return;
  1258. // We shouldn't get these notifications unless we're subscribed, right?
  1259. if ( m_pSOCache == NULL)
  1260. {
  1261. Assert( m_pSOCache );
  1262. return;
  1263. }
  1264. // Don't bother unless it's an incremental notification.
  1265. // For mass updates, we'll do everything more efficiently in one place
  1266. if ( eEvent != GCSDK::eSOCacheEvent_Incremental )
  1267. {
  1268. Assert( eEvent == GCSDK::eSOCacheEvent_Subscribed || eEvent == GCSDK::eSOCacheEvent_Resubscribed );
  1269. return;
  1270. }
  1271. CEconItem *pEconItem = (CEconItem *)pObject;
  1272. RemoveItem( pEconItem->GetItemID() );
  1273. #ifdef CLIENT_DLL
  1274. InventoryManager()->OnItemDeleted( this );
  1275. #endif
  1276. SendInventoryUpdateEvent();
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. // Purpose: This is our initial notification that this cache has been received
  1280. // from the server.
  1281. //-----------------------------------------------------------------------------
  1282. void CPlayerInventory::SOCacheSubscribed( SOID_t owner, GCSDK::ESOCacheEvent eEvent )
  1283. {
  1284. /** Removed for partner depot **/
  1285. return;
  1286. }
  1287. bool CInventoryManager::IsValidPlayerClass( equipped_class_t unClass )
  1288. {
  1289. const bool bResult = ItemSystem()->GetItemSchema()->IsValidClass( unClass );
  1290. AssertMsg( bResult, "Invalid player class!" );
  1291. return bResult;
  1292. }
  1293. bool CInventoryManager::IsValidSlot( equipped_slot_t unSlot )
  1294. {
  1295. const bool bResult = ItemSystem()->GetItemSchema()->IsValidItemSlot( unSlot );
  1296. AssertMsg( bResult, "Invalid item slot!" );
  1297. return bResult;
  1298. }
  1299. //-----------------------------------------------------------------------------
  1300. // Purpose: Removes the script item associated with this econ item
  1301. //-----------------------------------------------------------------------------
  1302. void CPlayerInventory::ValidateInventoryPositions( void )
  1303. {
  1304. #ifdef TF2
  1305. if ( engine->GetAppID() == 520 )
  1306. {
  1307. TFInventoryManager()->DeleteUnknowns( this );
  1308. }
  1309. #endif
  1310. }
  1311. //-----------------------------------------------------------------------------
  1312. // Purpose:
  1313. //-----------------------------------------------------------------------------
  1314. void CPlayerInventory::ItemHasBeenUpdated( CEconItemView *pItem, bool bUpdateAckFile, bool bWriteAckFile, EInventoryItemEvent eEventType )
  1315. {
  1316. #ifdef CLIENT_DLL
  1317. // Handle the clientside ack file
  1318. if ( bUpdateAckFile && !IsUnacknowledged(pItem->GetInventoryPosition()) )
  1319. {
  1320. if ( InventoryManager()->GetLocalInventory() == this )
  1321. {
  1322. InventoryManager()->SetAckedByGC( pItem, bWriteAckFile );
  1323. }
  1324. }
  1325. #endif
  1326. }
  1327. void CPlayerInventory::DefaultEquippedDefinitionHasBeenUpdated( CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinition )
  1328. {
  1329. }
  1330. void CPlayerInventory::MarkSetItemDescriptionsDirty( int nItemSetIndex )
  1331. {
  1332. int nInventoryCount = GetItemCount();
  1333. for ( int i = 0; i < nInventoryCount; i++ )
  1334. {
  1335. CEconItemView *pPotentialSetItem = GetItem( i );
  1336. if ( !pPotentialSetItem )
  1337. continue;
  1338. if ( pPotentialSetItem->GetItemSetIndex() == nItemSetIndex )
  1339. {
  1340. pPotentialSetItem->MarkDescriptionDirty();
  1341. }
  1342. }
  1343. }
  1344. //-----------------------------------------------------------------------------
  1345. // Purpose:
  1346. //-----------------------------------------------------------------------------
  1347. void CPlayerInventory::SOCacheUnsubscribed( GCSDK::SOID_t ID, GCSDK::ESOCacheEvent eEvent )
  1348. {
  1349. #ifdef _DEBUG
  1350. Msg("CPlayerInventory::SOCacheUnsubscribed %s [event = %u]\n", CSteamID( ID.ID() ).Render(), eEvent );
  1351. #endif
  1352. if ( ID != m_OwnerID )
  1353. return;
  1354. m_bCurrentlySubscribedToSteam = false;
  1355. /*
  1356. [ Vitaliy / Oct-2015 ] --- no longer dropping all references to everything just because we got unsubscribed of our
  1357. user's Steam SO cache. All the items are still valid to be used even though we might not be getting updates of new items.
  1358. This can happen if user's GC session drops for some reason, but GS session is still active.
  1359. m_pSOCache = NULL;
  1360. m_pRecipeCache = NULL;
  1361. m_Items.Purge();
  1362. m_aDefaultEquippedDefinitionItems.PurgeAndDeleteElements();
  1363. */
  1364. }
  1365. //-----------------------------------------------------------------------------
  1366. // Purpose: On the client this sends the "inventory_updated" event. On the server
  1367. // it does nothing.
  1368. //-----------------------------------------------------------------------------
  1369. void CPlayerInventory::SendInventoryUpdateEvent()
  1370. {
  1371. #ifdef CLIENT_DLL
  1372. IGameEvent *event = gameeventmanager->CreateEvent( "inventory_updated" );
  1373. if ( event )
  1374. {
  1375. gameeventmanager->FireEventClientSide( event );
  1376. }
  1377. #endif
  1378. #if defined( GAME_DLL ) && !defined( NO_STEAM_GAMECOORDINATOR )
  1379. extern void OnInventoryUpdatedForSteamID( CSteamID steamID );
  1380. OnInventoryUpdatedForSteamID( GetSteamIDFromSOID( m_OwnerID ) );
  1381. #endif
  1382. }
  1383. //-----------------------------------------------------------------------------
  1384. // Purpose: Fills out all the fields in the script item based on what's in the
  1385. // econ item
  1386. //-----------------------------------------------------------------------------
  1387. bool CPlayerInventory::FilloutItemFromEconItem( CEconItemView *pScriptItem, CEconItem *pEconItem )
  1388. {
  1389. // We need to detect the case where items have been updated & moved bags / positions.
  1390. uint32 iOldPos = pScriptItem->GetInventoryPosition();
  1391. bool bWasInThisBag = ItemShouldBeIncluded( iOldPos );
  1392. // Ignore items that this inventory doesn't care about
  1393. if ( !ItemShouldBeIncluded( pEconItem->GetInventoryToken() ) )
  1394. {
  1395. // The item has been moved out of this bag. Ensure our derived inventory classes know.
  1396. if ( bWasInThisBag )
  1397. {
  1398. // We need to update it before it's removed.
  1399. ItemHasBeenUpdated( pScriptItem, false, false, k_EInventoryItemDestroyed );
  1400. RemoveItem( pEconItem->GetItemID() );
  1401. }
  1402. return false;
  1403. }
  1404. pScriptItem->Init( pEconItem->GetDefinitionIndex(), pEconItem->GetQuality(), pEconItem->GetItemLevel(), pEconItem->GetAccountID() );
  1405. if ( !pScriptItem->IsValid() )
  1406. return false;
  1407. pScriptItem->SetItemID( pEconItem->GetItemID() );
  1408. pScriptItem->SetInventoryPosition( pEconItem->GetInventoryToken() );
  1409. OnItemChangedPosition( pScriptItem, iOldPos );
  1410. return true;
  1411. }
  1412. //-----------------------------------------------------------------------------
  1413. // Purpose:
  1414. //-----------------------------------------------------------------------------
  1415. void CPlayerInventory::DumpInventoryToConsole( bool bRoot )
  1416. {
  1417. if ( bRoot )
  1418. {
  1419. #ifdef CLIENT_DLL
  1420. Msg("(CLIENT) Inventory:\n");
  1421. #else
  1422. Msg("(SERVER) Inventory for account (%d):\n", GetSteamIDFromSOID( m_OwnerID ).GetAccountID() );
  1423. #endif
  1424. Msg(" Version: %llu:\n", m_pSOCache ? m_pSOCache->GetVersion() : -1 );
  1425. }
  1426. int iCount = m_Items.GetItemVector().Count();
  1427. Msg(" Num items: %d\n", iCount );
  1428. for ( int i = 0; i < iCount; i++ )
  1429. {
  1430. Msg( " %s (ID %llu)\n", m_Items.GetItemVector()[ i ]->GetStaticData()->GetDefinitionName(), m_Items.GetItemVector()[ i ]->GetItemID() );
  1431. }
  1432. iCount = m_aDefaultEquippedDefinitionItems.Count();
  1433. Msg(" Default equipped definitions: %d\n", iCount );
  1434. for ( int i = 0; i < iCount; i++ )
  1435. {
  1436. Msg( " %s (ID %llu)\n", m_aDefaultEquippedDefinitionItems[ i ]->GetStaticData()->GetDefinitionName(), m_Items.GetItemVector()[ i ]->GetItemID() );
  1437. }
  1438. }
  1439. //-----------------------------------------------------------------------------
  1440. // Purpose:
  1441. //-----------------------------------------------------------------------------
  1442. void CPlayerInventory::RemoveItem( itemid_t iItemID )
  1443. {
  1444. CEconItemView *pItem = GetInventoryItemByItemID( iItemID );
  1445. if ( pItem )
  1446. {
  1447. int nItemSet = pItem->GetItemSetIndex();
  1448. if ( nItemSet )
  1449. {
  1450. const CEconItemSetDefinition *pItemSetDef = GetItemSchema()->GetItemSetByIndex( nItemSet );
  1451. if ( pItemSetDef && pItemSetDef->m_bIsCollection )
  1452. {
  1453. MarkSetItemDescriptionsDirty( nItemSet );
  1454. }
  1455. }
  1456. m_Items.Remove( iItemID );
  1457. #ifdef _DEBUG
  1458. if ( item_inventory_debug.GetBool() )
  1459. {
  1460. DumpInventoryToConsole( true );
  1461. }
  1462. #endif
  1463. }
  1464. // Don't need to resort because items will still be in order
  1465. }
  1466. //-----------------------------------------------------------------------------
  1467. // Purpose: Finds the item in our inventory that matches the specified global index
  1468. //-----------------------------------------------------------------------------
  1469. CEconItemView *CPlayerInventory::GetInventoryItemByItemID( itemid_t iIndex ) const
  1470. {
  1471. // Early out for weapon ID 0
  1472. if ( iIndex == 0 )
  1473. return NULL;
  1474. ItemIdToItemMap_t::IndexType_t idx = m_Items.GetItemMap().Find( iIndex );
  1475. return m_Items.GetItemMap().IsValidIndex( idx ) ? m_Items.GetItemMap()[ idx ] : NULL;
  1476. /*
  1477. int iCount = m_aInventoryItems.Count();
  1478. for ( int i = 0; i < iCount; i++ )
  1479. {
  1480. if ( m_aInventoryItems[i]->GetItemID() == iIndex )
  1481. {
  1482. if ( pIndex )
  1483. {
  1484. *pIndex = i;
  1485. }
  1486. return m_aInventoryItems[i];
  1487. }
  1488. }
  1489. return NULL;
  1490. */
  1491. }
  1492. void CPlayerInventory::FindItemsByType( EItemType eType, CUtlVector< CEconItemView* >& outVec )
  1493. {
  1494. for ( int i = 0; i < m_Items.GetItemVector().Count(); ++i )
  1495. {
  1496. if ( m_Items.GetItemVector()[ i ]->GetItemDefinition()->GetItemType() == eType )
  1497. {
  1498. outVec.AddToTail( m_Items.GetItemVector()[ i ] );
  1499. }
  1500. }
  1501. }
  1502. //-----------------------------------------------------------------------------
  1503. // Purpose: Finds the item in our inventory in the specified position
  1504. //-----------------------------------------------------------------------------
  1505. CEconItemView *CPlayerInventory::GetItemByPosition( int iPosition, int *pIndex )
  1506. {
  1507. int iCount = m_Items.GetItemVector().Count();
  1508. for ( int i = 0; i < iCount; i++ )
  1509. {
  1510. if ( m_Items.GetItemVector()[ i ]->GetInventoryPosition() == ( unsigned int ) iPosition )
  1511. {
  1512. if ( pIndex )
  1513. {
  1514. *pIndex = i;
  1515. }
  1516. return m_Items.GetItemVector()[ i ];
  1517. }
  1518. }
  1519. return NULL;
  1520. }
  1521. //-----------------------------------------------------------------------------
  1522. // Purpose: Get the index for the item in our inventory utlvector
  1523. //-----------------------------------------------------------------------------
  1524. int CPlayerInventory::GetIndexForItem( CEconItemView *pItem )
  1525. {
  1526. int iCount = m_Items.GetItemVector().Count();
  1527. for ( int i = 0; i < iCount; i++ )
  1528. {
  1529. if ( m_Items.GetItemVector()[ i ]->GetItemID() == pItem->GetItemID() )
  1530. return i;
  1531. }
  1532. return -1;
  1533. }
  1534. //-----------------------------------------------------------------------------
  1535. // Purpose: Get the item object cache data for the specified item
  1536. //-----------------------------------------------------------------------------
  1537. CEconItem *CPlayerInventory::GetSOCDataForItem( itemid_t iItemID )
  1538. {
  1539. if ( iItemID == 0 )
  1540. return NULL;
  1541. CEconItem* pData = NULL;
  1542. if ( !m_pSOCache )
  1543. {
  1544. pData = GetEconItemFromStringTable( iItemID );
  1545. }
  1546. #ifdef CLIENT_DLL
  1547. // Don't access the live inventory data when playing a demo
  1548. bool bIsLiveBroadcast = engine->GetDemoPlaybackParameters() && engine->GetDemoPlaybackParameters()->m_bPlayingLiveRemoteBroadcast;
  1549. if ( ( engine->IsPlayingDemo() && !bIsLiveBroadcast ) || ( engine->IsHLTV() && this != InventoryManager()->GetLocalInventory() ) )
  1550. return pData;
  1551. #endif
  1552. if ( m_pSOCache && !pData )
  1553. {
  1554. CEconItem soIndex;
  1555. soIndex.SetItemID( iItemID );
  1556. pData = (CEconItem*) m_pSOCache->FindSharedObject( soIndex );
  1557. }
  1558. return pData;
  1559. }
  1560. const CEconItem *CPlayerInventory::GetSOCDataForItem( itemid_t iItemID ) const
  1561. {
  1562. if ( iItemID == 0 )
  1563. return NULL;
  1564. CEconItem* pData = NULL;
  1565. if ( !m_pSOCache )
  1566. {
  1567. pData = GetEconItemFromStringTable( iItemID );
  1568. }
  1569. if ( m_pSOCache && !pData )
  1570. {
  1571. CEconItem soIndex;
  1572. soIndex.SetItemID( iItemID );
  1573. pData = (CEconItem*) m_pSOCache->FindSharedObject( soIndex );
  1574. }
  1575. return pData;
  1576. }
  1577. #if defined (_DEBUG) && defined(CLIENT_DLL)
  1578. CON_COMMAND_F( item_deleteall, "WARNING: Removes all of the items in your inventory.", FCVAR_CHEAT )
  1579. {
  1580. CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
  1581. if ( !pInventory )
  1582. return;
  1583. int iCount = pInventory->GetItemCount();
  1584. for ( int i = 0; i < iCount; i++ )
  1585. {
  1586. CEconItemView *pItem = pInventory->GetItem(i);
  1587. if ( pItem )
  1588. {
  1589. InventoryManager()->DeleteItem( pItem->GetItemID() );
  1590. }
  1591. }
  1592. InventoryManager()->UpdateLocalInventory();
  1593. }
  1594. #endif
  1595. //-----------------------------------------------------------------------------
  1596. // Purpose:
  1597. //-----------------------------------------------------------------------------
  1598. uint32 CPlayerInventory::GetItemCount( uint32 unItemDef )
  1599. {
  1600. int iOwnedCount = 0;
  1601. int iCount = GetItemCount();
  1602. for ( int i = 0; i < iCount; i++ )
  1603. {
  1604. CEconItemView *pTmp = GetItem( i );
  1605. if ( !pTmp )
  1606. continue;
  1607. if ( pTmp->GetItemDefinition()->GetDefinitionIndex() == unItemDef )
  1608. iOwnedCount++;
  1609. }
  1610. return iOwnedCount;
  1611. }
  1612. CEconItemView* CPlayerInventory::FindDefaultEquippedDefinitionItemBySlot( int iClass, int iSlot ) const
  1613. {
  1614. uint32 nSlotValue = iClass * LOADOUT_POSITION_COUNT + iSlot;
  1615. FOR_EACH_VEC( m_aDefaultEquippedDefinitionItems, i )
  1616. {
  1617. if ( m_aDefaultEquippedDefinitionItems[ i ]->GetInventoryPosition() == nSlotValue )
  1618. {
  1619. return m_aDefaultEquippedDefinitionItems[ i ];
  1620. }
  1621. }
  1622. return NULL;
  1623. }
  1624. bool CPlayerInventory::GetDefaultEquippedDefinitionItemSlotByDefinitionIndex( item_definition_index_t nDefIndex, int nClass, int &nSlot )
  1625. {
  1626. FOR_EACH_VEC( m_aDefaultEquippedDefinitionItems, i )
  1627. {
  1628. if ( m_aDefaultEquippedDefinitionItems[ i ]->GetItemDefinition()->GetDefinitionIndex() == nDefIndex )
  1629. {
  1630. int nClassTemp = m_aDefaultEquippedDefinitionItems[ i ]->GetInventoryPosition() / LOADOUT_POSITION_COUNT;
  1631. if ( nClassTemp == nClass )
  1632. {
  1633. nSlot = m_aDefaultEquippedDefinitionItems[ i ]->GetInventoryPosition() - nClass * LOADOUT_POSITION_COUNT;
  1634. return true;
  1635. }
  1636. }
  1637. }
  1638. return false;
  1639. }
  1640. void CPlayerInventory::SetDefaultEquippedDefinitionItemBySlot( int iClass, int iSlot, item_definition_index_t iDefIndex )
  1641. {
  1642. uint32 nInventoryPosition = iClass * LOADOUT_POSITION_COUNT + iSlot;
  1643. FOR_EACH_VEC( m_aDefaultEquippedDefinitionItems, i )
  1644. {
  1645. CEconItemView *pItemView = m_aDefaultEquippedDefinitionItems[ i ];
  1646. if ( pItemView->GetInventoryPosition() == nInventoryPosition )
  1647. {
  1648. if ( iDefIndex == 0 )
  1649. {
  1650. delete m_aDefaultEquippedDefinitionItems[ i ];
  1651. m_aDefaultEquippedDefinitionItems.Remove( i );
  1652. return;
  1653. }
  1654. else
  1655. {
  1656. pItemView->Init( iDefIndex, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
  1657. return;
  1658. }
  1659. }
  1660. }
  1661. if ( iDefIndex == 0 || iSlot == INVALID_EQUIPPED_SLOT )
  1662. return;
  1663. CEconItemView *pNewItem = new CEconItemView;
  1664. pNewItem->Init( iDefIndex, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
  1665. if ( !pNewItem->IsValid() )
  1666. return;
  1667. int nIndex = m_aDefaultEquippedDefinitionItems.AddToTail( pNewItem );
  1668. m_aDefaultEquippedDefinitionItems[ nIndex ]->SetInventoryPosition( nInventoryPosition );
  1669. }
  1670. //-----------------------------------------------------------------------------
  1671. // Purpose:
  1672. //-----------------------------------------------------------------------------
  1673. int CPlayerInventory::GetRecipeCount() const
  1674. {
  1675. const CUtlMap<int, CEconCraftingRecipeDefinition *, int, CDefLess<int> >& mapRecipes = ItemSystem()->GetItemSchema()->GetRecipeDefinitionMap();
  1676. return mapRecipes.Count();
  1677. }
  1678. //-----------------------------------------------------------------------------
  1679. // Purpose:
  1680. //-----------------------------------------------------------------------------
  1681. const CEconCraftingRecipeDefinition *CPlayerInventory::GetRecipeDef( int iIndex ) const
  1682. {
  1683. if ( !m_pSOCache )
  1684. return NULL;
  1685. if ( iIndex < 0 || iIndex >= GetRecipeCount() )
  1686. return NULL;
  1687. const CUtlMap<int, CEconCraftingRecipeDefinition *, int, CDefLess<int> >& mapRecipes = ItemSystem()->GetItemSchema()->GetRecipeDefinitionMap();
  1688. // Store off separate index for "number of items iterated over" in case something
  1689. // deletes from the recipes map out from under us.
  1690. int j = 0;
  1691. FOR_EACH_MAP_FAST( mapRecipes, i )
  1692. {
  1693. if ( j == iIndex )
  1694. return mapRecipes[i];
  1695. j++;
  1696. }
  1697. return NULL;
  1698. }
  1699. //-----------------------------------------------------------------------------
  1700. // Purpose:
  1701. //-----------------------------------------------------------------------------
  1702. const CEconCraftingRecipeDefinition *CPlayerInventory::GetRecipeDefByDefIndex( uint16 iDefIndex ) const
  1703. {
  1704. if ( !m_pSOCache )
  1705. return NULL;
  1706. // check always-known recipes
  1707. const CUtlMap<int, CEconCraftingRecipeDefinition *, int, CDefLess<int> >& mapRecipes = ItemSystem()->GetItemSchema()->GetRecipeDefinitionMap();
  1708. int i = mapRecipes.Find( iDefIndex );
  1709. if ( i != mapRecipes.InvalidIndex() )
  1710. return mapRecipes[i];
  1711. return NULL;
  1712. }
  1713. int CPlayerInventory::GetMaxCraftIngredientsNeeded( const CUtlVector< itemid_t >& vecCraftItems ) const
  1714. {
  1715. int nMax = 0;
  1716. int nPossible = GetPossibleCraftResultsCount( vecCraftItems );
  1717. for ( int i = 0; i < nPossible; ++i )
  1718. {
  1719. const CEconCraftingRecipeDefinition *pRecipe = GetPossibleCraftResult( vecCraftItems, i );
  1720. if ( nMax < pRecipe->GetTotalInputItemsRequired() )
  1721. {
  1722. nMax = pRecipe->GetTotalInputItemsRequired();
  1723. }
  1724. }
  1725. return nMax;
  1726. }
  1727. void CPlayerInventory::GetMarketCraftCompletionLink( const CUtlVector< itemid_t >& vecCraftItems, char *pchLink, int nNumChars ) const
  1728. {
  1729. int nCollection = -2;
  1730. bool bWeapons = false;
  1731. bool bNonWeapons = false;
  1732. bool bStatTrak = false;
  1733. FOR_EACH_VEC( vecCraftItems, nCraftItem )
  1734. {
  1735. const CEconItem *pEconItem = GetSOCDataForItem( vecCraftItems[ nCraftItem ] );
  1736. if ( !pEconItem )
  1737. continue;
  1738. if ( ( StringHasPrefix( pEconItem->GetItemDefinition()->GetDefinitionName(), "weapon_" ) ) )
  1739. {
  1740. bWeapons = true;
  1741. }
  1742. else
  1743. {
  1744. bNonWeapons = true;
  1745. }
  1746. if ( !bStatTrak )
  1747. {
  1748. static CSchemaAttributeDefHandle pAttr_KillEater( "kill eater" );
  1749. if ( pEconItem->FindAttribute( pAttr_KillEater ) )
  1750. bStatTrak = true;
  1751. }
  1752. if ( nCollection )
  1753. {
  1754. // Found the first collection type
  1755. nCollection = pEconItem->GetItemSetIndex();
  1756. }
  1757. else if ( nCollection != pEconItem->GetItemSetIndex() )
  1758. {
  1759. // Found more than 1 collection type
  1760. nCollection = -1;
  1761. }
  1762. }
  1763. int nRarity = -2;
  1764. int nPossibleCount = GetPossibleCraftResultsCount( vecCraftItems );
  1765. // We can only match a collection if all the items have a matching collection and there's at leas 1 possible craft outcome
  1766. bool bMatchCollection = nCollection > 0 && nPossibleCount > 0;
  1767. for ( int i = 0; i < nPossibleCount; ++i )
  1768. {
  1769. const CEconCraftingRecipeDefinition *pRecipe = GetPossibleCraftResult( vecCraftItems, i );
  1770. // Can only do a rarity if everything is all weapons or all non-weapons since they localize differently
  1771. if ( ( bWeapons && !bNonWeapons ) || ( !bWeapons && bNonWeapons ) )
  1772. {
  1773. const CUtlVector< CItemSelectionCriteria > *pInputItems = pRecipe->GetInputItems();
  1774. FOR_EACH_VEC( *pInputItems, nInput )
  1775. {
  1776. const CItemSelectionCriteria *pInput = &((*pInputItems)[ nInput ]);
  1777. // RARITY
  1778. int nTempRarity = -1;
  1779. if ( pInput->BRaritySet() )
  1780. {
  1781. nTempRarity = pInput->GetRarity();
  1782. }
  1783. else
  1784. {
  1785. const char *pchRarity = pInput->GetValueForFirstConditionOfFieldName( "*rarity" );
  1786. if ( pchRarity )
  1787. {
  1788. const CEconItemRarityDefinition *pRarity = GetItemSchema()->GetRarityDefinitionByName( pchRarity );
  1789. if ( pRarity )
  1790. {
  1791. nTempRarity = pRarity->GetDBValue();
  1792. }
  1793. }
  1794. }
  1795. if ( nRarity == -2 )
  1796. {
  1797. nRarity = nTempRarity;
  1798. }
  1799. else if ( nRarity != nTempRarity )
  1800. {
  1801. nRarity = -1;
  1802. }
  1803. }
  1804. }
  1805. if ( bMatchCollection )
  1806. {
  1807. const CUtlVector< CItemSelectionCriteria > *pOutputItems = &(pRecipe->GetOutputItems());
  1808. FOR_EACH_VEC( *pOutputItems, nOutput )
  1809. {
  1810. const CItemSelectionCriteria *pOutput = &((*pOutputItems)[ nOutput ]);
  1811. if ( pOutput->GetValueForFirstConditionOfFieldName( "*match_set_rarity" ) == NULL )
  1812. {
  1813. bMatchCollection = false;
  1814. }
  1815. }
  1816. }
  1817. }
  1818. V_snprintf( pchLink, nNumChars, "http://%ssteamcommunity.com/market/search?appid=730&lock_appid=730&q=",
  1819. ( steamapicontext->SteamUtils()->GetConnectedUniverse() == k_EUniversePublic ) ? "" : "beta." );
  1820. if ( nRarity >= 0 || bMatchCollection || bStatTrak )
  1821. {
  1822. // Special search tags
  1823. // http://steamcommunity.com/market/search?appid=730&q=%22The+Arms+Deal+Collection%22+%22Mil-Spec+Grade%22
  1824. const CEconItemRarityDefinition *pRarity = GetItemSchema()->GetRarityDefinition( nRarity );
  1825. if ( pRarity )
  1826. { // see "econ_assetapi_context.cpp : Rarity Tag"
  1827. // &category_730_Rarity%5B%5D=tag_Rarity_Ancient_Weapon
  1828. V_strncat( pchLink, "&category_730_Rarity%5B%5D=tag_", nNumChars );
  1829. const char *pchLocKey = pRarity->GetLocKey();
  1830. if ( ( nRarity != 7 ) && bWeapons )
  1831. pchLocKey = pRarity->GetWepLocKey();
  1832. V_strncat( pchLink, pchLocKey, nNumChars );
  1833. }
  1834. if ( bMatchCollection )
  1835. {
  1836. // &category_730_ItemSet%5B%5D=tag_set_bravo_i
  1837. const IEconItemSetDefinition *pCollection = GetItemSchema()->GetItemSet( nCollection );
  1838. if ( pCollection )
  1839. { // see "econ_assetapi_context.cpp : ItemSet"
  1840. char const *pchName = pCollection->GetName();
  1841. V_strncat( pchLink, "&category_730_ItemSet%5B%5D=tag_", nNumChars );
  1842. V_strncat( pchLink, pchName, nNumChars );
  1843. }
  1844. }
  1845. if ( bStatTrak )
  1846. {
  1847. V_strncat( pchLink, "&category_730_Quality%5B%5D=tag_strange", nNumChars );
  1848. }
  1849. // Replace spaces with +
  1850. char *pCurrentChar = pchLink;
  1851. while ( *pCurrentChar != '\0' )
  1852. {
  1853. if ( *pCurrentChar == ' ' )
  1854. {
  1855. *pCurrentChar = '+';
  1856. }
  1857. pCurrentChar++;
  1858. }
  1859. }
  1860. V_strncat( pchLink, "&", nNumChars ); // this allows us to defeat PHP redirects duplicating GETPARAMS!
  1861. }
  1862. int CPlayerInventory::GetPossibleCraftResultsCount( const CUtlVector< itemid_t >& vecCraftItems ) const
  1863. {
  1864. if ( m_nTargetRecipe >= 0 )
  1865. return 1;
  1866. CUtlVector< CEconItem* > vecCraftEconItems;
  1867. FOR_EACH_VEC( vecCraftItems, i )
  1868. {
  1869. const CEconItem *pEconItem = GetSOCDataForItem( vecCraftItems[ i ] );
  1870. if ( !pEconItem )
  1871. continue;
  1872. vecCraftEconItems.AddToTail( const_cast< CEconItem* >( pEconItem ) );
  1873. }
  1874. return GetPossibleCraftResultsCount( vecCraftEconItems );
  1875. }
  1876. int CPlayerInventory::GetPossibleCraftResultsCount( const CUtlVector< CEconItem* >& vecCraftEconItems ) const
  1877. {
  1878. if ( m_nTargetRecipe >= 0 )
  1879. return 1;
  1880. int nPossibleRecipes = 0;
  1881. int nRecipeCount = GetRecipeCount();
  1882. for ( int i = 0; i < nRecipeCount; ++i )
  1883. {
  1884. const CEconCraftingRecipeDefinition *pRecipe = GetRecipeDef( i );
  1885. if ( !pRecipe || pRecipe->IsDisabled() )
  1886. continue;
  1887. if ( m_nTargetRecipe < -1 && m_nTargetRecipe != pRecipe->GetFilter() )
  1888. continue;
  1889. // Early out if it uses less items than we're crafting
  1890. if ( pRecipe->GetTotalInputItemsRequired() < vecCraftEconItems.Count() )
  1891. continue;
  1892. // If it has any items do they conflict?
  1893. if ( vecCraftEconItems.Count() > 0 && !pRecipe->ItemListMatchesInputs( vecCraftEconItems, true ) )
  1894. continue;
  1895. nPossibleRecipes++;
  1896. }
  1897. return nPossibleRecipes;
  1898. }
  1899. const CEconCraftingRecipeDefinition *CPlayerInventory::GetPossibleCraftResult( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const
  1900. {
  1901. if ( m_nTargetRecipe >= 0 )
  1902. {
  1903. if ( nIndex > 0 )
  1904. return NULL;
  1905. return GetRecipeDef( m_nTargetRecipe );
  1906. }
  1907. int nPossibleRecipes = 0;
  1908. CUtlVector< CEconItem* > vecCraftEconItems;
  1909. FOR_EACH_VEC( vecCraftItems, i )
  1910. {
  1911. const CEconItem *pEconItem = GetSOCDataForItem( vecCraftItems[ i ] );
  1912. if ( !pEconItem )
  1913. continue;
  1914. vecCraftEconItems.AddToTail( const_cast< CEconItem* >( pEconItem ) );
  1915. }
  1916. int nRecipeCount = GetRecipeCount();
  1917. for ( int i = 0; i < nRecipeCount; ++i )
  1918. {
  1919. const CEconCraftingRecipeDefinition *pRecipe = GetRecipeDef( i );
  1920. if ( !pRecipe || pRecipe->IsDisabled() )
  1921. continue;
  1922. if ( m_nTargetRecipe < -1 && m_nTargetRecipe != pRecipe->GetFilter() )
  1923. continue;
  1924. // Early out if it uses less items than we're crafting
  1925. if ( pRecipe->GetTotalInputItemsRequired() < vecCraftEconItems.Count() )
  1926. continue;
  1927. // If it has any items do they conflict?
  1928. if ( vecCraftEconItems.Count() > 0 && !pRecipe->ItemListMatchesInputs( vecCraftEconItems, true ) )
  1929. continue;
  1930. if ( nPossibleRecipes == nIndex )
  1931. {
  1932. return pRecipe;
  1933. }
  1934. nPossibleRecipes++;
  1935. }
  1936. return NULL;
  1937. }
  1938. int CPlayerInventory::GetPossibleCraftResultID( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const
  1939. {
  1940. const CEconCraftingRecipeDefinition *pRecipe = GetPossibleCraftResult( vecCraftItems, nIndex );
  1941. if ( !pRecipe )
  1942. return -1;
  1943. return pRecipe->GetDefinitionIndex();
  1944. }
  1945. const wchar_t* CPlayerInventory::GetPossibleCraftResultName( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const
  1946. {
  1947. const CEconCraftingRecipeDefinition *pRecipe = GetPossibleCraftResult( vecCraftItems, nIndex );
  1948. if ( !pRecipe )
  1949. return L"";
  1950. return pRecipe->GetLocName();
  1951. }
  1952. const wchar_t* CPlayerInventory::GetPossibleCraftResultDescription( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const
  1953. {
  1954. const CEconCraftingRecipeDefinition *pRecipe = GetPossibleCraftResult( vecCraftItems, nIndex );
  1955. if ( !pRecipe )
  1956. return L"";
  1957. return pRecipe->GetLocDescription();
  1958. }
  1959. bool CPlayerInventory::CanAddToCraftTarget( const CUtlVector< itemid_t >& vecCraftItems, itemid_t nNewItem ) const
  1960. {
  1961. const CEconCraftingRecipeDefinition *pRecipe = NULL;
  1962. if ( m_nTargetRecipe < 0 )
  1963. {
  1964. if ( m_nTargetRecipe != CRAFT_FILTER_COLLECT && m_nTargetRecipe != CRAFT_FILTER_TRADEUP )
  1965. {
  1966. return true;
  1967. }
  1968. }
  1969. else
  1970. {
  1971. pRecipe = GetRecipeDef( m_nTargetRecipe );
  1972. if ( !pRecipe || pRecipe->IsDisabled() )
  1973. return false;
  1974. }
  1975. const CEconItem *pEconItem = GetSOCDataForItem( nNewItem );
  1976. if ( !pEconItem )
  1977. return false;
  1978. int nSet = pEconItem->GetItemSetIndex();
  1979. CUtlVector< CEconItem* > vecCraftEconItems;
  1980. FOR_EACH_VEC( vecCraftItems, i )
  1981. {
  1982. const CEconItem *pTempEconItem = GetSOCDataForItem( vecCraftItems[ i ] );
  1983. if ( !pTempEconItem )
  1984. continue;
  1985. // You can't put an item in twice!
  1986. if ( vecCraftItems[ i ] == nNewItem )
  1987. return false;
  1988. if ( m_nTargetRecipe == CRAFT_FILTER_COLLECT )
  1989. {
  1990. // Collecting requires items from the same set!
  1991. if ( nSet != pTempEconItem->GetItemSetIndex() )
  1992. {
  1993. return false;
  1994. }
  1995. }
  1996. else if ( m_nTargetRecipe == CRAFT_FILTER_TRADEUP )
  1997. {
  1998. // Trading up requires items from the same rarity!
  1999. if ( pEconItem->GetRarity() != pTempEconItem->GetRarity() )
  2000. {
  2001. return false;
  2002. }
  2003. }
  2004. vecCraftEconItems.AddToTail( const_cast< CEconItem* >( pTempEconItem ) );
  2005. }
  2006. vecCraftEconItems.AddToTail( const_cast< CEconItem* >( pEconItem ) );
  2007. if ( !pRecipe )
  2008. {
  2009. return GetPossibleCraftResultsCount( vecCraftEconItems ) > 0;
  2010. }
  2011. // Early out if we already have enough items in the recipe
  2012. if ( pRecipe->GetTotalInputItemsRequired() < vecCraftEconItems.Count() )
  2013. return false;
  2014. // Does the items + the new one work for the target?
  2015. return pRecipe->ItemListMatchesInputs( vecCraftEconItems, true );
  2016. }
  2017. bool CPlayerInventory::IsCraftReady( const CUtlVector< itemid_t >& vecCraftItems, int16 &nRecipe ) const
  2018. {
  2019. CUtlVector< CEconItem* > vecCraftEconItems;
  2020. FOR_EACH_VEC( vecCraftItems, i )
  2021. {
  2022. const CEconItem *pEconItem = GetSOCDataForItem( vecCraftItems[ i ] );
  2023. if ( !pEconItem )
  2024. continue;
  2025. vecCraftEconItems.AddToTail( const_cast< CEconItem* >( pEconItem ) );
  2026. }
  2027. if ( m_nTargetRecipe >= 0 )
  2028. {
  2029. const CEconCraftingRecipeDefinition *pRecipe = GetRecipeDef( m_nTargetRecipe );
  2030. if ( !pRecipe || pRecipe->IsDisabled() )
  2031. return false;
  2032. // Early out if it uses less items than we're crafting
  2033. if ( pRecipe->GetTotalInputItemsRequired() < vecCraftEconItems.Count() )
  2034. return false;
  2035. // If it has any items do they conflict?
  2036. if ( vecCraftEconItems.Count() > 0 && !pRecipe->ItemListMatchesInputs( vecCraftEconItems ) )
  2037. return false;
  2038. nRecipe = m_nTargetRecipe;
  2039. return true;
  2040. }
  2041. bool bIsReady = false;
  2042. int nRecipeCount = GetRecipeCount();
  2043. for ( int i = 0; i < nRecipeCount; ++i )
  2044. {
  2045. const CEconCraftingRecipeDefinition *pRecipe = GetRecipeDef( i );
  2046. if ( !pRecipe || pRecipe->IsDisabled() )
  2047. continue;
  2048. // Early out if it uses less items than we're crafting
  2049. if ( pRecipe->GetTotalInputItemsRequired() < vecCraftEconItems.Count() )
  2050. continue;
  2051. // If it has any items do they conflict?
  2052. if ( vecCraftEconItems.Count() > 0 && !pRecipe->ItemListMatchesInputs( vecCraftEconItems ) )
  2053. continue;
  2054. if ( !bIsReady )
  2055. {
  2056. bIsReady = true;
  2057. nRecipe = pRecipe->GetDefinitionIndex();
  2058. }
  2059. else
  2060. {
  2061. // Found 2 valid recipes!
  2062. return false;
  2063. }
  2064. }
  2065. return bIsReady;
  2066. }
  2067. void CPlayerInventory::CraftIngredients( const CUtlVector< itemid_t >& vecCraftItems ) const
  2068. {
  2069. /** Removed for partner depot **/
  2070. }
  2071. void CPlayerInventory::ClearItemCustomName( itemid_t iIndex )
  2072. {
  2073. /** Removed for partner depot **/
  2074. }
  2075. void CPlayerInventory::WearItemSticker( itemid_t iIndex, int nSlot, float flStickerWearCurrent )
  2076. {
  2077. /** Removed for partner depot **/
  2078. }
  2079. void CPlayerInventory::CItemContainers::Add( CEconItemView* pItem )
  2080. {
  2081. Assert( DbgValidate() );
  2082. m_vecInventoryItems.AddToTail( pItem );
  2083. m_mapItemIDToItemView.Insert( pItem->GetItemID(), pItem );
  2084. Assert( DbgValidate() );
  2085. }
  2086. void CPlayerInventory::CItemContainers::Remove( itemid_t ullItemID )
  2087. {
  2088. Assert( DbgValidate() );
  2089. CUtlVectorFixedGrowable< CEconItemView *, 2 > arrPurgeAndDeleteItems;
  2090. for ( ItemIdToItemMap_t::IndexType_t uiMapIdx = m_mapItemIDToItemView.Find( ullItemID );
  2091. ( uiMapIdx != m_mapItemIDToItemView.InvalidIndex() ) &&
  2092. ( m_mapItemIDToItemView.Key( uiMapIdx ) == ullItemID );
  2093. )
  2094. {
  2095. arrPurgeAndDeleteItems.AddToTail( m_mapItemIDToItemView.Element( uiMapIdx ) );
  2096. ItemIdToItemMap_t::IndexType_t uiNextMapIdx = m_mapItemIDToItemView.NextInorder( uiMapIdx );
  2097. m_vecInventoryItems.FindAndRemove( m_mapItemIDToItemView.Element( uiMapIdx ) );
  2098. m_mapItemIDToItemView.RemoveAt( uiMapIdx );
  2099. uiMapIdx = uiNextMapIdx;
  2100. }
  2101. arrPurgeAndDeleteItems.PurgeAndDeleteElements();
  2102. Assert( DbgValidate() );
  2103. }
  2104. void CPlayerInventory::CItemContainers::Purge()
  2105. {
  2106. m_mapItemIDToItemView.Purge();
  2107. m_vecInventoryItems.PurgeAndDeleteElements();
  2108. }
  2109. // Make sure each element in vector can be found in map and the pointers match, vise versa
  2110. // If we add more containers this will need to be rewritten to require all are synced.
  2111. bool CPlayerInventory::CItemContainers::DbgValidate() const
  2112. {
  2113. CUtlRBTree< CEconItemView *, int, CDefLess< CEconItemView * > > rbItems;
  2114. FOR_EACH_VEC( m_vecInventoryItems, i )
  2115. {
  2116. int idx = rbItems.InsertIfNotFound( m_vecInventoryItems[ i ] );
  2117. if ( idx == rbItems.InvalidIndex() )
  2118. {
  2119. DebuggerBreakIfDebugging();
  2120. return false;
  2121. }
  2122. }
  2123. FOR_EACH_MAP( m_mapItemIDToItemView, i )
  2124. {
  2125. CEconItemView *pElem = m_mapItemIDToItemView.Element( i );
  2126. if ( pElem->GetItemID() != m_mapItemIDToItemView.Key( i ) )
  2127. {
  2128. DebuggerBreakIfDebugging();
  2129. return false;
  2130. }
  2131. if ( !rbItems.Remove( pElem ) )
  2132. {
  2133. DebuggerBreakIfDebugging();
  2134. return false;
  2135. }
  2136. }
  2137. if ( rbItems.Count() )
  2138. {
  2139. DebuggerBreakIfDebugging();
  2140. return false;
  2141. }
  2142. return true;
  2143. }