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.

1803 lines
56 KiB

  1. //========= Copyright (c) 1996-2003, Valve LLC, All rights reserved. ============
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "cstrike15_item_inventory.h"
  8. #include "econ_entity_creation.h"
  9. #include "cstrike15_item_system.h"
  10. #include "vgui/ILocalize.h"
  11. #include "tier3/tier3.h"
  12. #ifdef CLIENT_DLL
  13. #include "c_cs_player.h"
  14. #include "itempickup_scaleform.h"
  15. #include "keyvalues.h"
  16. #include "filesystem.h"
  17. #include "ienginevgui.h"
  18. #include "cs_gamerules.h"
  19. //#include "econ_notifications.h"
  20. //#include "econ/econ_item_preset.h"
  21. #else
  22. #include "cs_player.h"
  23. #endif
  24. #include "econ_game_account_client.h"
  25. #include "gcsdk/gcclientsdk.h"
  26. #include "econ_gcmessages.h"
  27. #include "cs_gamerules.h"
  28. #include "econ_item.h"
  29. #include "game_item_schema.h"
  30. #ifdef CLIENT_DLL
  31. #include "matchmaking/imatchframework.h"
  32. #endif // CLIENT_DLL
  33. // memdbgon must be the last include file in a .cpp file!!!
  34. #include "tier0/memdbgon.h"
  35. using namespace GCSDK;
  36. #ifdef CLIENT_DLL
  37. ConVar econ_debug_loadout_ui( "econ_debug_loadout_ui", "0", FCVAR_DEVELOPMENTONLY, "Show debug data when players change their loadout." );
  38. //-----------------------------------------------------------------------------
  39. //class CEconNotification_HasNewItems : public CEconNotification
  40. //{
  41. //public:
  42. // CEconNotification_HasNewItems() : CEconNotification()
  43. // {
  44. // m_bHasTriggered = false;
  45. // }
  46. //
  47. // ~CEconNotification_HasNewItems()
  48. // {
  49. // if ( !m_bHasTriggered )
  50. // {
  51. // m_bHasTriggered = true;
  52. // PortalInventoryManager()->ShowItemsPickedUp( true, true, true );
  53. // }
  54. // }
  55. //
  56. // virtual void MarkForDeletion()
  57. // {
  58. // m_bHasTriggered = true;
  59. //
  60. // CEconNotification::MarkForDeletion();
  61. // }
  62. //
  63. // virtual bool CanBeTriggered() { return true; }
  64. // virtual void Trigger()
  65. // {
  66. // m_bHasTriggered = true;
  67. // PortalInventoryManager()->ShowItemsPickedUp( true );
  68. // MarkForDeletion();
  69. // }
  70. //
  71. // static bool IsNotificationType( CEconNotification *pNotification ) { return dynamic_cast< CEconNotification_HasNewItems *>( pNotification ) != NULL; }
  72. //
  73. //private:
  74. //
  75. // bool m_bHasTriggered;
  76. //};
  77. #endif
  78. //-----------------------------------------------------------------------------
  79. // Purpose:
  80. //-----------------------------------------------------------------------------
  81. bool AreSlotsConsideredIdentical( int iBaseSlot, int iTestSlot )
  82. {
  83. if ( iBaseSlot == LOADOUT_POSITION_SPRAY0 )
  84. {
  85. return ( iTestSlot >= LOADOUT_POSITION_SPRAY0 && iTestSlot <= LOADOUT_POSITION_SPRAY0 /*LOADOUT_POSITION_SPRAY3*/ );
  86. }
  87. if ( iBaseSlot == LOADOUT_POSITION_SECONDARY0 )
  88. {
  89. return ( iTestSlot >= LOADOUT_POSITION_SECONDARY0 && iTestSlot <= LOADOUT_POSITION_SECONDARY5 );
  90. }
  91. if ( iBaseSlot == LOADOUT_POSITION_SMG0 )
  92. {
  93. return ( iTestSlot >= LOADOUT_POSITION_SMG0 && iTestSlot <= LOADOUT_POSITION_SMG5 );
  94. }
  95. if ( iBaseSlot == LOADOUT_POSITION_RIFLE0 )
  96. {
  97. return ( iTestSlot >= LOADOUT_POSITION_RIFLE0 && iTestSlot <= LOADOUT_POSITION_RIFLE5 );
  98. }
  99. if ( iBaseSlot == LOADOUT_POSITION_HEAVY0 )
  100. {
  101. return ( iTestSlot >= LOADOUT_POSITION_HEAVY0 && iTestSlot <= LOADOUT_POSITION_HEAVY5 );
  102. }
  103. if ( iBaseSlot == LOADOUT_POSITION_GRENADE0 )
  104. {
  105. return ( iTestSlot >= LOADOUT_POSITION_GRENADE0 && iTestSlot <= LOADOUT_POSITION_GRENADE5 );
  106. }
  107. if ( iBaseSlot == LOADOUT_POSITION_EQUIPMENT0 )
  108. {
  109. return ( iTestSlot >= LOADOUT_POSITION_EQUIPMENT0 && iTestSlot <= LOADOUT_POSITION_EQUIPMENT5 );
  110. }
  111. if ( iBaseSlot == LOADOUT_POSITION_MISC0 )
  112. {
  113. return ( iTestSlot >= LOADOUT_POSITION_MISC0 && iTestSlot <= LOADOUT_POSITION_MISC5 );
  114. }
  115. return iBaseSlot == iTestSlot;
  116. }
  117. //-----------------------------------------------------------------------------
  118. CCSInventoryManager g_CSInventoryManager;
  119. CInventoryManager *InventoryManager( void )
  120. {
  121. return &g_CSInventoryManager;
  122. }
  123. CCSInventoryManager *CSInventoryManager( void )
  124. {
  125. return &g_CSInventoryManager;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose:
  129. //-----------------------------------------------------------------------------
  130. CCSInventoryManager::CCSInventoryManager( void )
  131. {
  132. #ifdef CLIENT_DLL
  133. m_pLocalInventory = NULL;
  134. #endif
  135. // Do not renumber these indices. Stored in database.
  136. COMPILE_TIME_ASSERT( LOADOUT_POSITION_MELEE == 0 );
  137. COMPILE_TIME_ASSERT( LOADOUT_POSITION_C4 == 1 );
  138. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SECONDARY0 == 2 );
  139. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SECONDARY1 == 3 );
  140. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SECONDARY2 == 4 );
  141. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SECONDARY3 == 5 );
  142. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SECONDARY4 == 6 );
  143. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SMG0 == 8 );
  144. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SMG1 == 9 );
  145. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SMG2 == 10 );
  146. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SMG3 == 11 );
  147. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SMG4 == 12 );
  148. COMPILE_TIME_ASSERT( LOADOUT_POSITION_RIFLE0 == 14 );
  149. COMPILE_TIME_ASSERT( LOADOUT_POSITION_RIFLE1 == 15 );
  150. COMPILE_TIME_ASSERT( LOADOUT_POSITION_RIFLE2 == 16 );
  151. COMPILE_TIME_ASSERT( LOADOUT_POSITION_RIFLE3 == 17 );
  152. COMPILE_TIME_ASSERT( LOADOUT_POSITION_RIFLE4 == 18 );
  153. COMPILE_TIME_ASSERT( LOADOUT_POSITION_RIFLE5 == 19 );
  154. COMPILE_TIME_ASSERT( LOADOUT_POSITION_HEAVY0 == 20 );
  155. COMPILE_TIME_ASSERT( LOADOUT_POSITION_HEAVY1 == 21 );
  156. COMPILE_TIME_ASSERT( LOADOUT_POSITION_HEAVY2 == 22 );
  157. COMPILE_TIME_ASSERT( LOADOUT_POSITION_HEAVY3 == 23 );
  158. COMPILE_TIME_ASSERT( LOADOUT_POSITION_HEAVY4 == 24 );
  159. COMPILE_TIME_ASSERT( LOADOUT_POSITION_CLOTHING_HANDS == 41 );
  160. COMPILE_TIME_ASSERT( LOADOUT_POSITION_MUSICKIT == 54 );
  161. COMPILE_TIME_ASSERT( LOADOUT_POSITION_FLAIR0 == 55 );
  162. COMPILE_TIME_ASSERT( LOADOUT_POSITION_SPRAY0 == 56 );
  163. }
  164. bool CCSInventoryManager::Init( void )
  165. {
  166. #ifdef CLIENT_DLL
  167. Assert( !m_pLocalInventory );
  168. m_pLocalInventory = dynamic_cast< CCSPlayerInventory* >( GeneratePlayerInventoryObject() );
  169. #endif
  170. return BaseClass::Init();
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Purpose:
  174. //-----------------------------------------------------------------------------
  175. void CCSInventoryManager::PostInit( void )
  176. {
  177. BaseClass::PostInit();
  178. GenerateBaseItems();
  179. }
  180. void CCSInventoryManager::Shutdown( void )
  181. {
  182. #ifdef CLIENT_DLL
  183. Assert( m_pLocalInventory );
  184. DestroyPlayerInventoryObject( m_pLocalInventory );
  185. m_pLocalInventory = NULL;
  186. #endif
  187. BaseClass::Shutdown();
  188. }
  189. void CCSInventoryManager::LevelInitPreEntity( void )
  190. {
  191. BaseClass::LevelInitPreEntity();
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Purpose: Generate & store the base item details for each class & loadout slot
  195. //-----------------------------------------------------------------------------
  196. void CCSInventoryManager::GenerateBaseItems( void )
  197. {
  198. for ( int iTeam = 0; iTeam < LOADOUT_COUNT; iTeam++ )
  199. {
  200. for ( int slot = 0; slot < LOADOUT_POSITION_COUNT; slot++ )
  201. {
  202. bool bEligibleForDefaultItem = false; // The reason these checks are here for "bEligibleForDefaultItem" is because SlotContainsBaseItems function is shitty, doesn't take team argument and by default returns "true" which is not the desired behavior for allteams :( [fixing it at 9PM before shipping, good for now]
  203. switch ( iTeam )
  204. {
  205. case TEAM_CT:
  206. case TEAM_TERRORIST:
  207. bEligibleForDefaultItem = true;
  208. break;
  209. }
  210. switch ( slot )
  211. {
  212. case LOADOUT_POSITION_MUSICKIT:
  213. bEligibleForDefaultItem = true;
  214. break;
  215. }
  216. if ( !bEligibleForDefaultItem )
  217. {
  218. m_pBaseLoadoutItems[iTeam][slot].Invalidate();
  219. continue;
  220. }
  221. baseitemcriteria_t pCriteria;
  222. pCriteria.iClass = iTeam;
  223. pCriteria.iSlot = slot;
  224. int iItemDef = CStrike15ItemSystem()->GenerateBaseItem( &pCriteria );
  225. if ( iItemDef != INVALID_ITEM_INDEX )
  226. {
  227. /*
  228. IHasAttributes *pItemInterface = dynamic_cast<IHasAttributes *>(pItem);
  229. if ( pItemInterface )
  230. {
  231. CEconItemView *pScriptItem = pItemInterface->GetAttributeManager()->GetItem();
  232. Msg("============================================\n");
  233. Msg("Inventory: Generating base item for %s, slot %s...\n", g_aPlayerClassNames_NonLocalized[iTeam], g_szLoadoutStrings[slot] );
  234. Msg("Generated: %s \"%s\"\n", g_szQualityStrings[pScriptItem->GetItemQuality()], pEnt->GetClassname() );
  235. char tempstr[1024];
  236. g_pVGuiLocalize->ConvertUnicodeToANSI( pScriptItem->GetAttributeDescription(), tempstr, sizeof(tempstr) );
  237. Msg("%s", tempstr );
  238. Msg("\n============================================\n");
  239. }
  240. */
  241. m_pBaseLoadoutItems[iTeam][slot].Init( iItemDef, AE_USE_SCRIPT_VALUE, AE_USE_SCRIPT_VALUE, false );
  242. }
  243. else
  244. {
  245. m_pBaseLoadoutItems[iTeam][slot].Invalidate();
  246. }
  247. }
  248. }
  249. }
  250. #ifdef CLIENT_DLL
  251. int g_nLoadoutActionBatchNum = 0;
  252. int g_nLoadoutActionBatchLastFrame = 0;
  253. //-----------------------------------------------------------------------------
  254. // Purpose:
  255. //-----------------------------------------------------------------------------
  256. bool CCSInventoryManager::EquipItemInLoadout( int iTeam, int iSlot, itemid_t iItemID, bool bSwap /*= false*/ )
  257. {
  258. if ( !steamapicontext || !steamapicontext->SteamUser() )
  259. return false;
  260. if ( econ_debug_loadout_ui.GetBool() && g_nLoadoutActionBatchLastFrame != gpGlobals->framecount )
  261. {
  262. ConColorMsg( Color( 255, 0, 255, 255 ), "\nLOADOUT ACTION BATCH #%i\n", g_nLoadoutActionBatchNum );
  263. g_nLoadoutActionBatchNum++;
  264. g_nLoadoutActionBatchLastFrame = gpGlobals->framecount;
  265. }
  266. Assert( m_pLocalInventory );
  267. // If they pass in a 0 item id, we're just clearing the loadout slot
  268. bool bIsBaseItem = CombinedItemIdIsDefIndexAndPaint( iItemID );
  269. uint16 nLowDWord = CombinedItemIdGetDefIndex( iItemID );
  270. if ( iItemID == 0 || ( bIsBaseItem && ( nLowDWord == 0 ) ) )
  271. {
  272. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "LOADOUT Clear slot: %i\n", iSlot );
  273. m_pLocalInventory->SetDefaultEquippedDefinitionItemBySlot( iTeam, iSlot, 0 );
  274. return m_pLocalInventory->ClearLoadoutSlot( iTeam, iSlot );
  275. }
  276. CEconItemView *pBaseItem = CSInventoryManager()->GetBaseItemForTeam( iTeam, iSlot );
  277. bool bWillClearSlot = ( pBaseItem && pBaseItem->IsValid() && bIsBaseItem && pBaseItem->GetItemDefinition()->GetDefinitionIndex() == nLowDWord );
  278. bool bSwapClearedASlot = false;
  279. CEconItemView *pItem = NULL;
  280. const GameItemDefinition_t *pDef = NULL;
  281. if ( !bIsBaseItem )
  282. {
  283. pItem = m_pLocalInventory->GetInventoryItemByItemID( iItemID );
  284. if ( !pItem || !pItem->IsValid() )
  285. return false;
  286. pDef = pItem->GetStaticData();
  287. }
  288. else
  289. {
  290. pDef = dynamic_cast< const GameItemDefinition_t* >( GetItemSchema()->GetItemDefinition( nLowDWord ) );
  291. }
  292. if ( !pDef )
  293. return false;
  294. if ( bWillClearSlot && pDef->SharesSlot() )
  295. bWillClearSlot = false;
  296. // We check for validity on the GC when we equip items, but we can't really trust anyone
  297. // and so we check here as well.
  298. Assert( AreSlotsConsideredIdentical( pDef->GetLoadoutSlot( iTeam ), iSlot ) );
  299. if ( !AreSlotsConsideredIdentical( pDef->GetLoadoutSlot( iTeam ), iSlot ) ||
  300. ( pDef->GetDefaultLoadoutSlot() > -1
  301. && pDef->GetDefaultLoadoutSlot() != LOADOUT_POSITION_SPRAY0 // all spray slots are considered identical for equipping (unlike weapons categories)
  302. && pDef->GetDefaultLoadoutSlot() != iSlot ) ||
  303. !pDef->CanBeUsedByTeam( iTeam ) )
  304. {
  305. return false;
  306. }
  307. // Do we already have an item equipped in this slot?
  308. CEconItemView *pItemAlreadyInPosition = NULL;
  309. if ( m_pLocalInventory->m_LoadoutItems[ iTeam ][ iSlot ] != LOADOUT_SLOT_USE_BASE_ITEM )
  310. {
  311. pItemAlreadyInPosition = m_pLocalInventory->GetInventoryItemByItemID( m_pLocalInventory->m_LoadoutItems[ iTeam ][ iSlot ] );
  312. }
  313. if ( bSwap )
  314. {
  315. int nSwapSlot = INVALID_EQUIPPED_SLOT;
  316. if ( pItem )
  317. {
  318. nSwapSlot = pItem->GetEquippedPositionForClass( iTeam );
  319. }
  320. else
  321. {
  322. m_pLocalInventory->GetDefaultEquippedDefinitionItemSlotByDefinitionIndex( nLowDWord, iTeam, nSwapSlot );
  323. }
  324. if ( nSwapSlot != INVALID_EQUIPPED_SLOT )
  325. {
  326. if ( pItemAlreadyInPosition && pItemAlreadyInPosition->IsValid() )
  327. {
  328. // Are we trying to equip the item that's already there?
  329. if ( pItem && pItem->GetItemID() == pItemAlreadyInPosition->GetItemID() )
  330. return true;
  331. pItemAlreadyInPosition->UpdateEquippedState( iTeam, nSwapSlot );
  332. m_pLocalInventory->m_LoadoutItems[ iTeam ][ nSwapSlot ] = pItemAlreadyInPosition->GetItemID();
  333. m_pLocalInventory->m_LoadoutItems[ iTeam ][ iSlot ] = LOADOUT_SLOT_USE_BASE_ITEM;
  334. if ( bWillClearSlot )
  335. {
  336. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "LOADOUT UniqueItem \"%s\" to slot: %i\n", pItemAlreadyInPosition->GetItemDefinition()->GetDefinitionName(), nSwapSlot );
  337. // Need to move this on the backend since a swap won't happen
  338. UpdateInventoryEquippedState( m_pLocalInventory, pItemAlreadyInPosition->GetItemID(), iTeam, nSwapSlot, false );
  339. }
  340. else
  341. {
  342. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "//LOADOUT UniqueItem \"%s\" swapped to slot: %i\n", pItemAlreadyInPosition->GetItemDefinition()->GetDefinitionName(), nSwapSlot );
  343. }
  344. }
  345. else
  346. {
  347. CEconItemView *pSwapItem = m_pLocalInventory->FindDefaultEquippedDefinitionItemBySlot( iTeam, iSlot );
  348. if ( pSwapItem )
  349. {
  350. CEconItemView *pBaseItem = CSInventoryManager()->GetBaseItemForTeam( iTeam, nSwapSlot );
  351. if ( pBaseItem && pBaseItem->IsValid() && pBaseItem->GetItemDefinition()->GetDefinitionIndex() == pSwapItem->GetItemDefinition()->GetDefinitionIndex() )
  352. {
  353. // Putting a default in the slot where it belongs... just clear it out
  354. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "LOADOUT Clear slot: %i\n", nSwapSlot );
  355. m_pLocalInventory->SetDefaultEquippedDefinitionItemBySlot( iTeam, nSwapSlot, 0 );
  356. m_pLocalInventory->ClearLoadoutSlot( iTeam, nSwapSlot );
  357. bSwapClearedASlot = true;
  358. }
  359. else
  360. {
  361. // There's a base item in this slot
  362. uint64 nSwapItemId = CombinedItemIdMakeFromDefIndexAndPaint( pSwapItem->GetItemDefinition()->GetDefinitionIndex(), 0 );
  363. m_pLocalInventory->SetDefaultEquippedDefinitionItemBySlot( iTeam, nSwapSlot, pSwapItem->GetItemDefinition()->GetDefinitionIndex() );
  364. if ( bWillClearSlot )
  365. {
  366. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "LOADOUT BaseItem \"%s\" to slot: %i\n", pSwapItem->GetItemDefinition()->GetDefinitionName(), nSwapSlot );
  367. // Need to move this on the backend since a swap won't happen
  368. UpdateInventoryEquippedState( m_pLocalInventory, nSwapItemId, iTeam, nSwapSlot, false );
  369. }
  370. else
  371. {
  372. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "//LOADOUT BaseItem \"%s\" swapped to slot: %i\n", pSwapItem->GetItemDefinition()->GetDefinitionName(), nSwapSlot );
  373. }
  374. }
  375. }
  376. m_pLocalInventory->m_LoadoutItems[ iTeam ][ nSwapSlot ] = LOADOUT_SLOT_USE_BASE_ITEM;
  377. }
  378. }
  379. else
  380. {
  381. if ( pItemAlreadyInPosition && pItemAlreadyInPosition->IsValid() )
  382. {
  383. pItemAlreadyInPosition->UpdateEquippedState( iTeam, INVALID_EQUIPPED_SLOT );
  384. }
  385. else
  386. {
  387. CEconItemView *pSwapItem = m_pLocalInventory->FindDefaultEquippedDefinitionItemBySlot( iTeam, iSlot );
  388. if ( pSwapItem )
  389. {
  390. m_pLocalInventory->SetDefaultEquippedDefinitionItemBySlot( iTeam, iSlot, 0 );
  391. }
  392. }
  393. }
  394. }
  395. else
  396. {
  397. if ( pItemAlreadyInPosition && pItemAlreadyInPosition->IsValid() )
  398. {
  399. UpdateInventoryEquippedState( m_pLocalInventory, pItemAlreadyInPosition->GetItemID(), iTeam, INVALID_EQUIPPED_SLOT );
  400. }
  401. }
  402. // Equip the new item
  403. if ( pItem )
  404. {
  405. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "LOADOUT UniqueItem \"%s\" to slot: %i\n", pDef->GetDefinitionName(), iSlot );
  406. pItem->UpdateEquippedState( iTeam, iSlot );
  407. m_pLocalInventory->m_LoadoutItems[ iTeam ][ iSlot ] = pItem->GetItemID();
  408. }
  409. else
  410. {
  411. if ( bWillClearSlot )
  412. {
  413. // Putting a default in the slot where it belongs... just clear it out
  414. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "LOADOUT Clear slot: %i\n", iSlot );
  415. m_pLocalInventory->SetDefaultEquippedDefinitionItemBySlot( iTeam, iSlot, 0 );
  416. return m_pLocalInventory->ClearLoadoutSlot( iTeam, iSlot );
  417. }
  418. if ( econ_debug_loadout_ui.GetBool() ) ConColorMsg( Color( 255, 0, 255, 255 ), "LOADOUT BaseItem \"%s\" to slot: %i\n", pDef->GetDefinitionName(), iSlot );
  419. m_pLocalInventory->SetDefaultEquippedDefinitionItemBySlot( iTeam, iSlot, nLowDWord );
  420. m_pLocalInventory->m_LoadoutItems[ iTeam ][ iSlot ] = LOADOUT_SLOT_USE_BASE_ITEM;
  421. }
  422. UpdateInventoryEquippedState( m_pLocalInventory, iItemID, iTeam, iSlot, bSwap && !bSwapClearedASlot );
  423. return true;
  424. }
  425. struct BaseItemToCheck_t
  426. {
  427. item_definition_index_t nDefIndex;
  428. int nSlot;
  429. BaseItemToCheck_t( item_definition_index_t p_nDefIndex, int p_nSlot )
  430. {
  431. nDefIndex = p_nDefIndex;
  432. nSlot = p_nSlot;
  433. }
  434. };
  435. bool CCSInventoryManager::CleanupDuplicateBaseItems( int iClass )
  436. {
  437. CUtlVector< BaseItemToCheck_t > vecBaseItemsToCheck;
  438. CUtlVector< item_definition_index_t > vecDefaultItems;
  439. for ( int nSlot = 0; nSlot < ARRAYSIZE( m_pLocalInventory->m_LoadoutItems[ iClass ] ); ++nSlot )
  440. {
  441. // Skip unique item slots
  442. if ( m_pLocalInventory->m_LoadoutItems[ iClass ][ nSlot ] != 0 )
  443. continue;
  444. CEconItemView *pBaseItem = m_pLocalInventory->FindDefaultEquippedDefinitionItemBySlot( iClass, nSlot );
  445. if ( pBaseItem && pBaseItem->IsValid() )
  446. {
  447. // Base item here
  448. vecBaseItemsToCheck.AddToTail( BaseItemToCheck_t( pBaseItem->GetItemDefinition()->GetDefinitionIndex(), nSlot ) );
  449. continue;
  450. }
  451. // This slot is using the default, check for duplicates
  452. CEconItemView *pDefault = GetBaseItemForTeam( iClass, nSlot );
  453. if ( pDefault && pDefault->IsValid() )
  454. {
  455. vecDefaultItems.AddToTail( pDefault->GetItemDefinition()->GetDefinitionIndex() );
  456. }
  457. }
  458. bool bFoundDuplicate = true;
  459. while ( bFoundDuplicate )
  460. {
  461. bFoundDuplicate = false;
  462. FOR_EACH_VEC( vecBaseItemsToCheck, i )
  463. {
  464. if ( vecDefaultItems.IsValidIndex( vecDefaultItems.Find( vecBaseItemsToCheck[ i ].nDefIndex ) ) )
  465. {
  466. // Found a matching default
  467. bFoundDuplicate = true;
  468. // Unequip the base
  469. EquipItemInLoadout( iClass, vecBaseItemsToCheck[ i ].nSlot, 0 );
  470. CEconItemView *pDefault = GetBaseItemForTeam( iClass, vecBaseItemsToCheck[ i ].nSlot );
  471. if ( pDefault && pDefault->IsValid() )
  472. {
  473. // Add the default to the list
  474. vecDefaultItems.AddToTail( pDefault->GetItemDefinition()->GetDefinitionIndex() );
  475. }
  476. // Remove this from the list
  477. vecBaseItemsToCheck.Remove( i );
  478. break;
  479. }
  480. }
  481. }
  482. return true;
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose: Fills out pList with all inventory items that could fit into the specified loadout slot for a given class
  486. //-----------------------------------------------------------------------------
  487. int CCSInventoryManager::GetAllUsableItemsForSlot( int iTeam, int iSlot, unsigned int unUsedEquipRegionMask, CUtlVector<CEconItemView*> *pList )
  488. {
  489. Assert( iTeam >= 0 && iTeam < LOADOUT_COUNT );
  490. Assert( iSlot >= -1 && iSlot < LOADOUT_POSITION_COUNT );
  491. Assert( m_pLocalInventory );
  492. int iCount = m_pLocalInventory->GetItemCount();
  493. for ( int i = 0; i < iCount; i++ )
  494. {
  495. CEconItemView *pItem = m_pLocalInventory->GetItem(i);
  496. const CCStrike15ItemDefinition *pItemData = pItem->GetStaticData();
  497. int nLoadoutSlot = pItem->GetStaticData()->GetLoadoutSlot(iTeam);
  498. if ( nLoadoutSlot != LOADOUT_POSITION_MISC0 && !pItemData->CanBeUsedByTeam(iTeam) )
  499. continue;
  500. // Passing in iSlot of -1 finds all items usable by the class
  501. if ( iSlot >= 0 && !AreSlotsConsideredIdentical( nLoadoutSlot, iSlot ) )
  502. continue;
  503. // Ignore unpack'd items
  504. if ( IsUnacknowledged( pItem->GetInventoryPosition() ) )
  505. continue;
  506. // Skip if it conflicts with equipped
  507. if ( pItemData->GetEquipRegionMask() & unUsedEquipRegionMask )
  508. continue;
  509. pList->AddToTail( m_pLocalInventory->GetItem(i) );
  510. }
  511. return pList->Count();
  512. }
  513. #endif // CLIENT_DLL
  514. //-----------------------------------------------------------------------------
  515. // Purpose:
  516. //-----------------------------------------------------------------------------
  517. CEconItemView *CCSInventoryManager::GetItemInLoadoutForTeam( int iTeam, int iSlot, CSteamID *pID )
  518. {
  519. #ifdef CLIENT_DLL
  520. if ( !pID )
  521. {
  522. // If they didn't specify a steamID, use the local player
  523. if ( !steamapicontext || !steamapicontext->SteamUser() )
  524. return NULL;
  525. CSteamID localSteamID = steamapicontext->SteamUser()->GetSteamID();
  526. pID = &localSteamID;
  527. }
  528. #endif
  529. if ( !pID )
  530. return NULL;
  531. CCSPlayerInventory *pInv = GetInventoryForPlayer( *pID );
  532. if ( !pInv )
  533. return GetBaseItemForTeam( iTeam, iSlot );
  534. return pInv->GetItemInLoadout( iTeam, iSlot );
  535. }
  536. //-----------------------------------------------------------------------------
  537. // Purpose:
  538. //-----------------------------------------------------------------------------
  539. CCSPlayerInventory *CCSInventoryManager::GetInventoryForPlayer( const CSteamID &playerID )
  540. {
  541. for ( int i = 0; i < m_pInventories.Count(); i++ )
  542. {
  543. if ( m_pInventories[i].pInventory->GetOwner() != playerID )
  544. continue;
  545. return assert_cast<CCSPlayerInventory*>( m_pInventories[i].pInventory );
  546. }
  547. return NULL;
  548. }
  549. #ifdef CLIENT_DLL
  550. //-----------------------------------------------------------------------------
  551. // Purpose:
  552. //-----------------------------------------------------------------------------
  553. int CCSInventoryManager::GetNumItemPickedUpItems( void )
  554. {
  555. Assert( m_pLocalInventory );
  556. int iResult = 0;
  557. int iCount = m_pLocalInventory->GetItemCount();
  558. for ( int i = 0; i < iCount; i++ )
  559. {
  560. CEconItemView *pItemView = m_pLocalInventory->GetItem(i);
  561. if ( pItemView->IsValid() && IsUnacknowledged( pItemView->GetInventoryPosition() ) )
  562. {
  563. // It also needs to be in our previously updated list of unacknowledged items or SF will fail at looking it up later
  564. if ( m_UnacknowledgedItems.Find( pItemView ) != m_UnacknowledgedItems.InvalidIndex() )
  565. {
  566. ++iResult;
  567. }
  568. }
  569. }
  570. return iResult;
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Purpose:
  574. //-----------------------------------------------------------------------------
  575. void CCSInventoryManager::UpdateUnacknowledgedItems( void )
  576. {
  577. CPlayerInventory *pLocalInv = GetLocalInventory();
  578. if ( !pLocalInv )
  579. return;
  580. CUtlVector< CEconItemView* > vecItemsAckedOnClientOnly;
  581. RebuildUnacknowledgedItemList( &vecItemsAckedOnClientOnly );
  582. // Acknowledge items on the GC that we've acked on the client but are still in the unacked position
  583. if ( vecItemsAckedOnClientOnly.Count() > 0 )
  584. {
  585. BeginBackpackPositionTransaction(); // Batch up the position information
  586. // We're not forcing the player to make room yet. Just show the pickup panel.
  587. for ( int i = 0; i < vecItemsAckedOnClientOnly.Count(); i++ )
  588. {
  589. // Then move it to the first empty backpack position
  590. SetItemBackpackPosition( vecItemsAckedOnClientOnly[i], 0, false, true );
  591. }
  592. EndBackpackPositionTransaction(); // Transmit the item update
  593. }
  594. }
  595. //-----------------------------------------------------------------------------
  596. // Purpose:
  597. //-----------------------------------------------------------------------------
  598. void CCSInventoryManager::AcknowledgeUnacknowledgedItems( void )
  599. {
  600. if ( !m_UnacknowledgedItems.Count() )
  601. return;
  602. BeginBackpackPositionTransaction(); // Batch up the position information
  603. // We're not forcing the player to make room yet. Just show the pickup panel.
  604. for ( int i = 0; i < m_UnacknowledgedItems.Count(); i++ )
  605. {
  606. SetAckedByClient( m_UnacknowledgedItems[i] );
  607. // int iMethod = GetUnacknowledgedReason( m_UnacknowledgedItems[i]->GetInventoryPosition() ) - 1;
  608. // if ( iMethod >= ARRAYSIZE( g_pszItemPickupMethodStringsUnloc ) || iMethod < 0 )
  609. // iMethod = 0;
  610. // EconUI()->Gamestats_ItemTransaction( IE_ITEM_RECEIVED, m_UnacknowledgedItems[i], g_pszItemPickupMethodStringsUnloc[iMethod] );
  611. // Then move it to the first empty backpack position
  612. SetItemBackpackPosition( m_UnacknowledgedItems[i], 0, false, true );
  613. }
  614. EndBackpackPositionTransaction(); // Transmit the item update
  615. }
  616. //-----------------------------------------------------------------------------
  617. // Purpose:
  618. //-----------------------------------------------------------------------------
  619. bool CCSInventoryManager::AcknowledgeUnacknowledgedItem( itemid_t ui64ItemID )
  620. {
  621. if ( !m_UnacknowledgedItems.Count() )
  622. return false;
  623. BeginBackpackPositionTransaction(); // Batch up the position information
  624. // We're not forcing the player to make room yet. Just show the pickup panel.
  625. FOR_EACH_VEC( m_UnacknowledgedItems, i )
  626. {
  627. if ( m_UnacknowledgedItems[i]->GetItemID() == ui64ItemID )
  628. {
  629. SetAckedByClient( m_UnacknowledgedItems[ i ] );
  630. SetItemBackpackPosition( m_UnacknowledgedItems[ i ], 0, false, true );
  631. EndBackpackPositionTransaction(); // Transmit the item update
  632. return true; // success!
  633. }
  634. }
  635. return false; // never found the item.
  636. }
  637. bool CCSInventoryManager::ShowItemsPickedUp( bool bForce, bool bReturnToGame, bool bNoPanel )
  638. {
  639. UpdateUnacknowledgedItems();
  640. if ( !m_UnacknowledgedItems.Count() )
  641. return false;//CheckForRoomAndForceDiscard();
  642. return true;
  643. }
  644. //-----------------------------------------------------------------------------
  645. // Purpose:
  646. //-----------------------------------------------------------------------------
  647. void CCSInventoryManager::ShowItemsCrafted( CUtlVector<itemid_t> *vecCraftedIndices )
  648. {
  649. /** Removed for partner depot **/
  650. }
  651. //-----------------------------------------------------------------------------
  652. // Purpose:
  653. //-----------------------------------------------------------------------------
  654. bool CCSInventoryManager::CheckForRoomAndForceDiscard( void )
  655. {
  656. /** Removed for partner depot **/
  657. return true;
  658. }
  659. #endif
  660. //-----------------------------------------------------------------------------
  661. // Purpose: Does a mapping to a "class" index based on a class index and a preset index, so that presets can be stored in the GC.
  662. //-----------------------------------------------------------------------------
  663. equipped_class_t CCSInventoryManager::DoClassMapping( equipped_class_t unClass, equipped_preset_t unPreset )
  664. {
  665. return ( unPreset << 8 ) | unClass;
  666. }
  667. //-----------------------------------------------------------------------------
  668. // Purpose: Returns the item data for the base item in the loadout slot for a given class
  669. //-----------------------------------------------------------------------------
  670. CEconItemView *CCSInventoryManager::GetBaseItemForTeam( int iTeam, int iSlot )
  671. {
  672. if ( iSlot < 0 || iSlot >= LOADOUT_POSITION_COUNT )
  673. return NULL;
  674. if ( iTeam < 0 || iTeam >= LOADOUT_COUNT )
  675. return NULL;
  676. return &m_pBaseLoadoutItems[iTeam][iSlot];
  677. }
  678. //-----------------------------------------------------------------------------
  679. // Purpose: Fills out the vector with the sets that are currently active on the specified player & class
  680. //-----------------------------------------------------------------------------
  681. void CCSInventoryManager::GetActiveSets( CUtlVector<const CEconItemSetDefinition *> *pItemSets, CSteamID steamIDForPlayer, int iTeam )
  682. {
  683. pItemSets->Purge();
  684. CEconItemSchema *pSchema = ItemSystem()->GetItemSchema();
  685. if ( !pSchema )
  686. return;
  687. // Loop through all the items we have equipped, and build a list of only set items
  688. // Accumulate a list of our equipped set items.
  689. CUtlVector<CEconItemView*> equippedSetItems;
  690. for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ )
  691. {
  692. CEconItemView *pItem = NULL;
  693. #ifdef GAME_DLL
  694. // On the server we need to look at what the player actually has equipped
  695. // because they might be on a tournament server that's using an item_whitelist
  696. CCSPlayer *pPlayer = ToCSPlayer( CBasePlayer::GetPlayerBySteamID( steamIDForPlayer ) );
  697. if ( pPlayer && pPlayer->Inventory() )
  698. {
  699. pItem = pPlayer->GetEquippedItemInLoadoutSlot( i );
  700. }
  701. #else
  702. pItem = CSInventoryManager()->GetItemInLoadoutForTeam( iTeam, i, &steamIDForPlayer );
  703. #endif
  704. if ( !pItem )
  705. continue;
  706. if ( pItem->GetItemSetIndex() < 0 )
  707. continue; // Ignore items that don't have set bonuses.
  708. equippedSetItems.AddToTail( pItem );
  709. }
  710. // Find out which sets to apply.
  711. CUtlVector<const char*> testedSets;
  712. for ( int inv = 0; inv < equippedSetItems.Count(); inv++ )
  713. {
  714. CEconItemView *pItem = equippedSetItems[inv];
  715. if ( !pItem )
  716. continue;
  717. const CEconItemSetDefinition *pItemSet = pSchema->GetItemSetByIndex( pItem->GetItemSetIndex() );
  718. if ( !pItemSet )
  719. continue;
  720. if ( testedSets.HasElement( pItemSet->m_pszName ) )
  721. continue; // Don't try to apply set bonuses we have already tested.
  722. testedSets.AddToTail( pItemSet->m_pszName );
  723. // Count how much of this set we have equipped.
  724. int iSetItemsEquipped = 0;
  725. FOR_EACH_VEC( pItemSet->m_ItemEntries, i )
  726. {
  727. unsigned int iIndex = pItemSet->m_ItemEntries[i].m_nItemDef;
  728. for ( int j=0; j<equippedSetItems.Count(); j++ )
  729. {
  730. CEconItemView *pTestItem = equippedSetItems[j];
  731. if ( iIndex == pTestItem->GetItemIndex() )
  732. {
  733. iSetItemsEquipped++;
  734. break;
  735. }
  736. }
  737. }
  738. if ( iSetItemsEquipped == pItemSet->m_ItemEntries.Count() )
  739. {
  740. // The entire set is equipped.
  741. pItemSets->AddToTail( pItemSet );
  742. }
  743. }
  744. }
  745. //-----------------------------------------------------------------------------
  746. // Purpose: We're generating a base item. We need to add the game-specific keys to the criteria so that it'll find the right base item.
  747. //-----------------------------------------------------------------------------
  748. void CCSInventoryManager::AddBaseItemCriteria( baseitemcriteria_t *pCriteria, CItemSelectionCriteria *pSelectionCriteria )
  749. {
  750. pSelectionCriteria->BAddCondition( "used_by_classes", k_EOperator_Subkey_Contains, ItemSystem()->GetItemSchema()->GetClassUsabilityStrings()[pCriteria->iClass], true );
  751. pSelectionCriteria->BAddCondition( "item_slot", k_EOperator_String_EQ, ItemSystem()->GetItemSchema()->GetLoadoutStrings()[pCriteria->iSlot], true );
  752. pSelectionCriteria->BAddCondition( "item_sub_position", k_EOperator_String_EQ, ItemSystem()->GetItemSchema()->GetLoadoutStringsSubPositions()[pCriteria->iSlot], true );
  753. }
  754. int CCSInventoryManager::GetSlotForBaseOrDefaultEquipped( int iClass, item_definition_index_t iDefIndex)
  755. {
  756. for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ )
  757. {
  758. CEconItemView* pItem = GetItemInLoadoutForTeam( iClass, i );
  759. if ( pItem &&
  760. pItem->IsValid() &&
  761. pItem->GetItemDefinition()->GetDefinitionIndex() == iDefIndex &&
  762. pItem->GetItemID() == 0 )
  763. {
  764. // Msg( " BASE OR DEFAULT ITEMS EQUIPPED: %s, %d\n", pItem->GetItemDefinition()->GetItemBaseName(), i);
  765. return i;
  766. }
  767. }
  768. return INVALID_EQUIPPED_SLOT;
  769. }
  770. #if defined ( CLIENT_DLL )
  771. void CCSInventoryManager::RebuildUnacknowledgedItemList( CUtlVector< CEconItemView* > * vecItemsAckedOnClientOnly /*null*/ )
  772. {
  773. CPlayerInventory *pLocalInv = GetLocalInventory();
  774. if ( !pLocalInv )
  775. return;
  776. m_UnacknowledgedItems.Purge();
  777. // Go through the root inventory and find any items that are in the "found" position
  778. int iCount = pLocalInv->GetItemCount();
  779. for ( int i = 0; i < iCount; i++ )
  780. {
  781. CEconItemView *pTmp = pLocalInv->GetItem( i );
  782. if ( !pTmp )
  783. continue;
  784. if ( pTmp->GetStaticData()->IsHidden() )
  785. continue;
  786. uint32 iPosition = pTmp->GetInventoryPosition();
  787. if ( IsUnacknowledged( iPosition ) == false )
  788. continue;
  789. if ( GetBackpackPositionFromBackend( iPosition ) != 0 )
  790. continue;
  791. if ( vecItemsAckedOnClientOnly )
  792. {
  793. // Now make sure we haven't got a clientside saved ack for this item.
  794. // This makes sure we don't show multiple pickups for items that we've found,
  795. // but haven't been able to move out of unack'd position due to the GC being unavailable.
  796. if ( HasBeenAckedByClient( pTmp ) )
  797. {
  798. vecItemsAckedOnClientOnly->AddToTail( pTmp );
  799. continue;
  800. }
  801. }
  802. m_UnacknowledgedItems.AddToTail( pTmp );
  803. }
  804. }
  805. CUtlVector<CEconItemView*> & CCSInventoryManager::GetUnacknowledgedItems( bool bRefreshList )
  806. {
  807. if ( bRefreshList )
  808. {
  809. RebuildUnacknowledgedItemList();
  810. }
  811. return m_UnacknowledgedItems;
  812. }
  813. #endif
  814. //-----------------------------------------------------------------------------
  815. // Purpose:
  816. //-----------------------------------------------------------------------------
  817. CCSPlayerInventory::CCSPlayerInventory()
  818. {
  819. memset( m_LoadoutItems, LOADOUT_SLOT_USE_BASE_ITEM, sizeof(m_LoadoutItems) );
  820. m_nActiveQuestID = 0;
  821. }
  822. static void Helper_NotifyMyPersonaInventoryUpdated( const CSteamID &steamIDOwner )
  823. {
  824. /** Removed for partner depot **/
  825. };
  826. //-----------------------------------------------------------------------------
  827. // Purpose:
  828. //-----------------------------------------------------------------------------
  829. void CCSPlayerInventory::SOCreated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent )
  830. {
  831. BaseClass::SOCreated( owner, pObject, eEvent );
  832. CSteamID steamIDOwner( owner.ID() );
  833. Helper_NotifyMyPersonaInventoryUpdated( steamIDOwner );
  834. if ( pObject->GetTypeID() == CEconItem::k_nTypeID )
  835. {
  836. CEconItem *pEconItem = ( CEconItem * ) pObject;
  837. // Update current quest if this is the op coin!
  838. switch ( pEconItem->GetDefinitionIndex() )
  839. {
  840. case MEDAL_SEASON_COIN_BRONZE:
  841. case MEDAL_SEASON_COIN_SILVER:
  842. case MEDAL_SEASON_COIN_GOLD:
  843. RefreshActiveQuestID();
  844. }
  845. }
  846. }
  847. //-----------------------------------------------------------------------------
  848. // Purpose:
  849. //-----------------------------------------------------------------------------
  850. void CCSPlayerInventory::SODestroyed( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent )
  851. {
  852. BaseClass::SODestroyed( owner, pObject, eEvent );
  853. CSteamID steamIDOwner( owner.ID() );
  854. Helper_NotifyMyPersonaInventoryUpdated( steamIDOwner );
  855. if ( pObject->GetTypeID() == CEconItem::k_nTypeID )
  856. {
  857. CEconItem *pEconItem = ( CEconItem * ) pObject;
  858. // Update current quest if this is the op coin!
  859. switch ( pEconItem->GetDefinitionIndex() )
  860. {
  861. case MEDAL_SEASON_COIN_BRONZE:
  862. case MEDAL_SEASON_COIN_SILVER:
  863. case MEDAL_SEASON_COIN_GOLD:
  864. RefreshActiveQuestID();
  865. }
  866. }
  867. }
  868. //-----------------------------------------------------------------------------
  869. // Purpose:
  870. //-----------------------------------------------------------------------------
  871. void CCSPlayerInventory::SOUpdated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent )
  872. {
  873. BaseClass::SOUpdated( owner, pObject, eEvent );
  874. CSteamID steamIDOwner( owner.ID() );
  875. Helper_NotifyMyPersonaInventoryUpdated( steamIDOwner );
  876. if ( pObject->GetTypeID() == CEconItem::k_nTypeID )
  877. {
  878. CEconItem *pEconItem = ( CEconItem * ) pObject;
  879. #ifdef CLIENT_DLL
  880. // Clear out any predicted backpack slots when items move into them
  881. int iBackpackPos = CSInventoryManager()->GetBackpackPositionFromBackend( pEconItem->GetInventoryToken() );
  882. CSInventoryManager()->PredictedBackpackPosFilled( iBackpackPos );
  883. if ( eEvent == eSOCacheEvent_Incremental )
  884. {
  885. pEconItem->SetSOUpdateFrame( gpGlobals->framecount );
  886. }
  887. #endif // CLIENT_DLL
  888. // Update current quest if this is the op coin!
  889. switch ( pEconItem->GetDefinitionIndex() )
  890. {
  891. case MEDAL_SEASON_COIN_BRONZE:
  892. case MEDAL_SEASON_COIN_SILVER:
  893. case MEDAL_SEASON_COIN_GOLD:
  894. RefreshActiveQuestID();
  895. }
  896. }
  897. }
  898. float CCSPlayerInventory::FindInventoryItemWithMaxAttributeValue( char const *szItemType, char const *szAttrClass, CEconItemView **ppItemFound /* = NULL */ )
  899. {
  900. if ( !szAttrClass || szAttrClass[ 0 ] == '\0' )
  901. return -1.0f;
  902. CSchemaAttributeDefHandle pAttr( szAttrClass );
  903. if ( !pAttr )
  904. return -1.0f;
  905. CEconItemView *pItemFound = NULL;
  906. float flReturnValue = -1.0f; // Nothing found yet
  907. CSchemaItemDefHandle hRequiredItem( szItemType );
  908. if ( hRequiredItem )
  909. {
  910. for ( int i = 0 ; i < GetItemCount() ; ++i )
  911. {
  912. CEconItemView *pItem = GetItem( i );
  913. Assert( pItem );
  914. if ( pItem->GetItemDefinition() == hRequiredItem )
  915. {
  916. if ( !pItemFound )
  917. {
  918. pItemFound = pItem;
  919. flReturnValue = 0.0f; // We at least found something
  920. }
  921. if ( pAttr->IsStoredAsInteger() )
  922. {
  923. uint32 unValue;
  924. if ( pItem->FindAttribute( pAttr, &unValue ) )
  925. {
  926. if ( flReturnValue < float( unValue ) )
  927. {
  928. pItemFound = pItem;
  929. flReturnValue = float( unValue );
  930. }
  931. }
  932. }
  933. else
  934. {
  935. float flFoundValue;
  936. if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttr, &flFoundValue ) )
  937. {
  938. if ( flReturnValue < flFoundValue )
  939. {
  940. pItemFound = pItem;
  941. flReturnValue = flFoundValue;
  942. }
  943. }
  944. }
  945. }
  946. }
  947. }
  948. if ( ppItemFound )
  949. {
  950. *ppItemFound = pItemFound;
  951. }
  952. return flReturnValue;
  953. }
  954. // DEPRECATED. Use version that takes CSchemaAttributeDefHandle instead. For Perf.
  955. void CCSPlayerInventory::FindInventoryItemsWithAttribute( char const *szAttrClass, CUtlVector< CEconItemView* > &foundItems, bool bMatchValue /*= false*/, uint32 unValue /*= 0*/ )
  956. {
  957. Assert(0); // DEPRECATED FUNCTION.
  958. if ( !szAttrClass || szAttrClass[ 0 ] == '\0' )
  959. return;
  960. CSchemaAttributeDefHandle pAttr( szAttrClass );
  961. if ( !pAttr )
  962. return;
  963. FindInventoryItemsWithAttribute( pAttr, foundItems, NULL, bMatchValue, unValue );
  964. }
  965. void CCSPlayerInventory::FindInventoryItemsWithAttribute( CSchemaAttributeDefHandle pAttr, CUtlVector< CEconItemView* > &foundItems, CUtlVector< CEconItemView* > *pVecSearchSet /* = NULL */, bool bMatchValue /*= false*/, uint32 unValue /*= 0*/ )
  966. {
  967. Assert( pAttr);
  968. if ( !pAttr )
  969. return;
  970. CUtlVector< CEconItemView* > itemSet;
  971. // if no search set was passed in, create a set of all inventory items
  972. if ( !pVecSearchSet )
  973. {
  974. for ( int i = 0; i < GetItemCount(); ++i )
  975. {
  976. CEconItemView *pItem = GetItem( i );
  977. Assert( pItem );
  978. itemSet.AddToTail( pItem );
  979. }
  980. pVecSearchSet = &itemSet;
  981. }
  982. FOR_EACH_VEC( (*pVecSearchSet), i )
  983. {
  984. if ( pAttr->IsStoredAsInteger() )
  985. {
  986. uint32 unItemAttrValue;
  987. if ( (*pVecSearchSet)[ i ]->FindAttribute( pAttr, &unItemAttrValue ) )
  988. {
  989. if ( !bMatchValue || ( unItemAttrValue == unValue ) )
  990. {
  991. foundItems.AddToTail( (*pVecSearchSet)[ i ] );
  992. }
  993. }
  994. }
  995. else
  996. {
  997. float flFoundValue;
  998. if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( (*pVecSearchSet)[ i ], pAttr, &flFoundValue ) )
  999. {
  1000. if ( !bMatchValue || ( *reinterpret_cast< uint32 const* >( &flFoundValue ) == unValue ) )
  1001. {
  1002. foundItems.AddToTail( (*pVecSearchSet)[ i ] );
  1003. }
  1004. }
  1005. }
  1006. }
  1007. }
  1008. itemid_t CCSPlayerInventory::GetActiveSeasonItemId( bool bCoin /* false is the Pass */ )
  1009. {
  1010. if ( !MEDAL_SEASON_ACCESS_ENABLED )
  1011. return 0;
  1012. // Season 2 access
  1013. CUtlVector< CEconItemView* > foundItems;
  1014. static CSchemaAttributeDefHandle pAttr( "season access" );
  1015. Assert( pAttr );
  1016. FindInventoryItemsWithAttribute( pAttr, foundItems, NULL, true, MEDAL_SEASON_ACCESS_VALUE );
  1017. FOR_EACH_VEC( foundItems, i )
  1018. {
  1019. CEconItemView *pItem = foundItems[ i ];
  1020. bool bAccessItemIsCoin = !pItem->GetItemDefinition()->IsToolAndNotACrate();
  1021. if ( bCoin == bAccessItemIsCoin )
  1022. {
  1023. return pItem->GetItemID();
  1024. }
  1025. }
  1026. return 0;
  1027. }
  1028. uint32 CCSPlayerInventory::GetActiveQuestID( void ) const
  1029. {
  1030. return m_nActiveQuestID;
  1031. }
  1032. void CCSPlayerInventory::RefreshActiveQuestID( void )
  1033. {
  1034. static CSchemaAttributeDefHandle pAttr( "season access" );
  1035. CUtlVector< CEconItemView* > foundItems;
  1036. FindInventoryItemsWithAttribute( pAttr, foundItems, NULL, true, MEDAL_SEASON_ACCESS_VALUE );
  1037. Assert( foundItems.Count() <= 1 );
  1038. if ( foundItems.Count() > 0 )
  1039. {
  1040. uint32 unQuestID = 0;
  1041. static CSchemaAttributeDefHandle pAttr_QuestID( "quest id" );
  1042. foundItems[ 0 ]->FindAttribute( pAttr_QuestID, &unQuestID );
  1043. m_nActiveQuestID = unQuestID;
  1044. }
  1045. else
  1046. {
  1047. m_nActiveQuestID = 0;
  1048. }
  1049. }
  1050. bool CCSPlayerInventory::IsEquipped( CEconItemView * pEconItemView, int nTeam )
  1051. {
  1052. if ( !pEconItemView || !pEconItemView->IsValid() )
  1053. return false;
  1054. bool bEquipped = false;
  1055. // if it's a base item
  1056. if ( !pEconItemView->GetItemID() )
  1057. {
  1058. const CCStrike15ItemDefinition *pItemDef = pEconItemView->GetItemDefinition();
  1059. if ( !pItemDef )
  1060. return false;
  1061. int nSlotOfTestItem = pItemDef->GetDefaultLoadoutSlot();
  1062. // Check to see if the defindex of the item we got matches the defindex of the
  1063. if ( nSlotOfTestItem > -1 )
  1064. {
  1065. CEconItemView *pItemInSlotOfTestItem = GetItemInLoadout( nTeam, nSlotOfTestItem );
  1066. if ( pItemInSlotOfTestItem && pItemInSlotOfTestItem->IsValid() )
  1067. {
  1068. // if the item that's in the test item's slot is a base item and has the same defindex then it's a match.
  1069. if ( ( pItemInSlotOfTestItem->GetItemID() == 0 ) &&
  1070. ( pItemInSlotOfTestItem->GetItemIndex() == pItemDef->GetDefinitionIndex() ) )
  1071. {
  1072. bEquipped = true;
  1073. }
  1074. }
  1075. }
  1076. }
  1077. else // otherwise if it's a real inventory item then the check is simple
  1078. {
  1079. bEquipped = pEconItemView->IsEquippedForClass( nTeam );
  1080. }
  1081. return bEquipped;
  1082. }
  1083. // For any team
  1084. bool CCSPlayerInventory::IsEquipped( CEconItemView *pEconItemView )
  1085. {
  1086. for ( int j = 0; j < TEAM_MAXCOUNT; j++ )
  1087. {
  1088. if ( IsEquipped( pEconItemView, j ) )
  1089. {
  1090. return true;
  1091. }
  1092. }
  1093. return false;
  1094. }
  1095. void CCSPlayerInventory::OnHasNewItems()
  1096. {
  1097. BaseClass::OnHasNewItems();
  1098. }
  1099. #ifdef _DEBUG
  1100. #ifdef CLIENT_DLL
  1101. //CON_COMMAND( cl_newitem_test, "Tests the new item ui notification." )
  1102. //{
  1103. // if ( steamapicontext == NULL || steamapicontext->SteamUser() == NULL )
  1104. // return;
  1105. //
  1106. // CEconNotification_HasNewItems *pNotification = new CEconNotification_HasNewItems();
  1107. // pNotification->SetText( "TF_HasNewItems" );
  1108. // pNotification->SetLifetime( engine->IsInGame() ? 7.0f : 60.0f );
  1109. // NotificationQueue_Add( pNotification );
  1110. //}
  1111. #endif
  1112. #endif // _DEBUG
  1113. //-----------------------------------------------------------------------------
  1114. // Purpose:
  1115. //-----------------------------------------------------------------------------
  1116. void CCSPlayerInventory::ValidateInventoryPositions( void )
  1117. {
  1118. BaseClass::ValidateInventoryPositions();
  1119. #ifdef CLIENT_DLL
  1120. bool bHasNewItems = false;
  1121. // First, check for duplicate positions
  1122. const CUtlVector<CEconItemView*> &vecItems = m_Items.GetItemVector();
  1123. FOR_EACH_VEC_BACK( vecItems, i )
  1124. {
  1125. uint32 iPosition = vecItems[ i ]->GetInventoryPosition();
  1126. // Waiting to be acknowledged?
  1127. if ( IsUnacknowledged(iPosition) )
  1128. {
  1129. bHasNewItems = true;
  1130. continue;
  1131. }
  1132. }
  1133. if ( bHasNewItems )
  1134. {
  1135. OnHasNewItems();
  1136. }
  1137. #endif
  1138. }
  1139. void CCSPlayerInventory::SOCacheSubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent )
  1140. {
  1141. BaseClass::SOCacheSubscribed( owner, eEvent );
  1142. }
  1143. #ifdef CLIENT_DLL
  1144. //-----------------------------------------------------------------------------
  1145. // Purpose:
  1146. //-----------------------------------------------------------------------------
  1147. void CCSPlayerInventory::ConvertOldFormatInventoryToNew( void )
  1148. {
  1149. uint32 iBackpackPos = 1;
  1150. // Loop through all items in the inventory. Move them all to the backpack, and in order.
  1151. int iCount = m_Items.GetItemVector().Count();
  1152. for ( int i = 0; i < iCount; i++ )
  1153. {
  1154. uint32 iPosition = m_Items.GetItemVector()[ i ]->GetInventoryPosition();
  1155. // Waiting to be acknowledged?
  1156. if ( IsUnacknowledged(iPosition) )
  1157. continue;
  1158. CSInventoryManager()->SetItemBackpackPosition( m_Items.GetItemVector()[ i ], iBackpackPos, true );
  1159. iBackpackPos++;
  1160. }
  1161. }
  1162. #endif
  1163. //-----------------------------------------------------------------------------
  1164. // Purpose:
  1165. //-----------------------------------------------------------------------------
  1166. void CCSPlayerInventory::DumpInventoryToConsole( bool bRoot )
  1167. {
  1168. if ( bRoot )
  1169. {
  1170. Msg("========================================\n");
  1171. #ifdef CLIENT_DLL
  1172. Msg("(CLIENT) Inventory:\n");
  1173. #else
  1174. Msg("(SERVER) Inventory for account (%d):\n", CSteamID( m_OwnerID.ID() ).GetAccountID() );
  1175. #endif
  1176. Msg(" Version: %llu:\n", m_pSOCache ? m_pSOCache->GetVersion() : -1 );
  1177. }
  1178. int iCount = m_Items.GetItemVector().Count();
  1179. Msg(" Num items: %d\n", iCount );
  1180. for ( int i = 0; i < iCount; i++ )
  1181. {
  1182. Msg(" %s (ID %llu) at backpack slot %d\n",
  1183. m_Items.GetItemVector()[ i ]->GetStaticData()->GetDefinitionName(),
  1184. m_Items.GetItemVector()[ i ]->GetItemID(),
  1185. CSInventoryManager()->GetBackpackPositionFromBackend( m_Items.GetItemVector()[ i ]->GetInventoryPosition() ) );
  1186. }
  1187. }
  1188. //-----------------------------------------------------------------------------
  1189. // Purpose: Returns the item in the specified loadout slot for a given team
  1190. //-----------------------------------------------------------------------------
  1191. CEconItemView *CCSPlayerInventory::GetItemInLoadout( int iTeam, int iSlot ) const
  1192. {
  1193. if ( iSlot < 0 || iSlot >= LOADOUT_POSITION_COUNT )
  1194. return NULL;
  1195. if ( iTeam < 0 || iTeam >= LOADOUT_COUNT )
  1196. return NULL;
  1197. // If we don't have an item in the loadout at that slot, we return the base item
  1198. if ( m_LoadoutItems[iTeam][iSlot] != LOADOUT_SLOT_USE_BASE_ITEM )
  1199. {
  1200. CEconItemView *pItem = GetInventoryItemByItemID( m_LoadoutItems[iTeam][iSlot] );
  1201. // To protect against users lying to the backend about the position of their items,
  1202. // we need to validate their position on the server when we retrieve them.
  1203. if ( pItem && AreSlotsConsideredIdentical( pItem->GetStaticData()->GetLoadoutSlot( iTeam ), iSlot ) )
  1204. return pItem;
  1205. }
  1206. CEconItemView *pDefaultItem = CSInventoryManager()->GetBaseItemForTeam( iTeam, iSlot );
  1207. CEconItemView *pItem = FindDefaultEquippedDefinitionItemBySlot( iTeam, iSlot );
  1208. if ( pItem && pItem->IsValid() )
  1209. {
  1210. if ( pItem->GetItemDefinition()->GetDefinitionIndex() == pDefaultItem->GetItemDefinition()->GetDefinitionIndex() )
  1211. {
  1212. // Just use the default if it's the same definition index
  1213. return pDefaultItem;
  1214. }
  1215. // Return the default that they've specifically equppied in that slot
  1216. return pItem;
  1217. }
  1218. // Fall back to the default
  1219. return pDefaultItem;
  1220. }
  1221. CEconItemView* CCSPlayerInventory::GetItemInLoadoutFilteredByProhibition( int iTeam, int iSlot ) const
  1222. {
  1223. CEconItemView *pItem = GetItemInLoadout( iTeam, iSlot );
  1224. if ( !pItem || !CSGameRules() )
  1225. return pItem;
  1226. /** Removed for partner depot **/
  1227. return pItem;
  1228. }
  1229. //-----------------------------------------------------------------------------
  1230. // Purpose:
  1231. //-----------------------------------------------------------------------------
  1232. CEconGameAccountClient *GetSOCacheGameAccountClient( CGCClientSharedObjectCache *pSOCache )
  1233. {
  1234. if ( !pSOCache )
  1235. return NULL;
  1236. CSharedObjectTypeCache *pTypeCache = pSOCache->FindTypeCache( CEconGameAccountClient::k_nTypeID );
  1237. if ( !pTypeCache || pTypeCache->GetCount() != 1 )
  1238. return NULL;
  1239. CEconGameAccountClient *pGameAccountClient = (CEconGameAccountClient*)pTypeCache->GetObject( 0 );
  1240. return pGameAccountClient;
  1241. }
  1242. //-----------------------------------------------------------------------------
  1243. // Purpose:
  1244. //-----------------------------------------------------------------------------
  1245. int CCSPlayerInventory::GetPreviewItemDef( void ) const
  1246. {
  1247. #if ECON_JOB_RENTAL_PREVIEW_SUPPORTED
  1248. CEconGameAccountClient *pGameAccountClient = GetSOCacheGameAccountClient( m_pSOCache );
  1249. if ( !pGameAccountClient )
  1250. return 0;
  1251. return pGameAccountClient->Obj().preview_item_def();
  1252. #else
  1253. return 0;
  1254. #endif
  1255. }
  1256. //-----------------------------------------------------------------------------
  1257. // Purpose:
  1258. //-----------------------------------------------------------------------------
  1259. bool CCSPlayerInventory::CanPurchaseItems( int iItemCount ) const
  1260. {
  1261. #if 1
  1262. return BaseClass::CanPurchaseItems( iItemCount );
  1263. #else
  1264. // If we're not a free trial account, we fall back to our default logic of "do
  1265. // we have enough empty slots?".
  1266. CEconGameAccountClient *pGameAccountClient = GetSOCacheGameAccountClient( m_pSOCache );
  1267. if ( !pGameAccountClient || !pGameAccountClient->Obj().trial_account() )
  1268. return BaseClass::CanPurchaseItems( iItemCount );
  1269. // We're a free trial account, so when we purchase these items, our inventory
  1270. // will actually expand. We check to make sure that we have room for these
  1271. // items against what will be our new maximum backpack size, not our current
  1272. // backpack limit.
  1273. int iNewItemCount = GetItemCount() + iItemCount,
  1274. iAfterPurchaseMaxItemCount = DEFAULT_NUM_BACKPACK_SLOTS
  1275. + (pGameAccountClient ? pGameAccountClient->Obj().additional_backpack_slots() : 0);
  1276. return iNewItemCount <= iAfterPurchaseMaxItemCount;
  1277. #endif
  1278. }
  1279. //-----------------------------------------------------------------------------
  1280. // Purpose:
  1281. //-----------------------------------------------------------------------------
  1282. int CCSPlayerInventory::GetMaxItemCount( void ) const
  1283. {
  1284. int iMaxItems = DEFAULT_NUM_BACKPACK_SLOTS;
  1285. CEconGameAccountClient *pGameAccountClient = GetSOCacheGameAccountClient( m_pSOCache );
  1286. if ( pGameAccountClient )
  1287. {
  1288. #if 0
  1289. if ( pGameAccountClient->Obj().trial_account() )
  1290. {
  1291. // Currently it thinks everyone is a trial account, so just give everyone the full space!
  1292. //iMaxItems = DEFAULT_NUM_BACKPACK_SLOTS_FREE_TRIAL_ACCOUNT;
  1293. }
  1294. #endif
  1295. iMaxItems += pGameAccountClient->Obj().additional_backpack_slots();
  1296. }
  1297. return Min( iMaxItems, MAX_NUM_BACKPACK_SLOTS );
  1298. }
  1299. #ifdef CLIENT_DLL
  1300. //-----------------------------------------------------------------------------
  1301. // Purpose: Removes any item in a loadout slot. If the slot has a base item,
  1302. // the player essentially returns to using that item.
  1303. //-----------------------------------------------------------------------------
  1304. bool CCSPlayerInventory::ClearLoadoutSlot( int iTeam, int iSlot )
  1305. {
  1306. /** Removed for partner depot **/
  1307. return true;
  1308. }
  1309. #endif // CLIENT_DLL
  1310. #ifdef CLIENT_DLL
  1311. //
  1312. // Inventory image provider for Scaleform
  1313. //
  1314. IScaleformInventoryImageProvider *g_pIScaleformInventoryImageProvider = NULL;
  1315. class CScaleformInventoryImageProviderImpl : public IScaleformInventoryImageProvider
  1316. {
  1317. public:
  1318. CScaleformInventoryImageProviderImpl()
  1319. {
  1320. m_mapItems2Owners.SetLessFunc( DefLessFunc( itemid_t ) );
  1321. Assert( !g_pIScaleformInventoryImageProvider );
  1322. g_pIScaleformInventoryImageProvider = this;
  1323. }
  1324. ~CScaleformInventoryImageProviderImpl()
  1325. {
  1326. Assert( g_pIScaleformInventoryImageProvider == this );
  1327. g_pIScaleformInventoryImageProvider = NULL;
  1328. }
  1329. public:
  1330. // Scaleform low-level image needs rgba bits of the inventory image (if it's ready)
  1331. virtual bool GetInventoryImageInfo( uint64 uiItemId, ImageInfo_t *pImageInfo )
  1332. {
  1333. CEconItemView *pItemView = FindOrCreateEconItemViewForItemID( uiItemId );
  1334. if ( !pItemView )
  1335. return false;
  1336. if ( pImageInfo )
  1337. {
  1338. pImageInfo->m_pvEconItemView = reinterpret_cast< void *>( pItemView );
  1339. pImageInfo->m_bufImageDataRGBA = pItemView->GetInventoryImageRgba( ECON_ITEM_GENERATED_ICON_WIDTH, ECON_ITEM_GENERATED_ICON_HEIGHT, InventoryImageReadyCallback );
  1340. pImageInfo->m_pDefaultIconName = pItemView->GetStaticData() ? pItemView->GetStaticData()->GetIconDefaultImage() : NULL;
  1341. pImageInfo->m_nWidth = ECON_ITEM_GENERATED_ICON_WIDTH;
  1342. pImageInfo->m_nHeight = ECON_ITEM_GENERATED_ICON_HEIGHT;
  1343. }
  1344. return true;
  1345. }
  1346. static void InventoryImageReadyCallback( const CEconItemView *pItemView, CUtlBuffer &rawImageRgba, int nWidth, int nHeight, uint64 nItemID )
  1347. {
  1348. g_pScaleformUI->InventoryImageUpdate( nItemID, g_pIScaleformInventoryImageProvider );
  1349. }
  1350. CEconItemView * FindOrCreateEconItemViewForItemID( uint64 uiItemId )
  1351. {
  1352. CEconItemView *pItemView = NULL;
  1353. // Reference def/paint items ID structure:
  1354. if ( CombinedItemIdIsDefIndexAndPaint( uiItemId ) )
  1355. {
  1356. uint16 iPaintIndex = CombinedItemIdGetPaint( uiItemId );
  1357. uint16 iDefIndex = CombinedItemIdGetDefIndex( uiItemId );
  1358. uint8 ub1 = CombinedItemIdGetUB1( uiItemId );
  1359. pItemView = InventoryManager()->FindOrCreateReferenceEconItem( iDefIndex, iPaintIndex, ub1 );
  1360. Assert( pItemView && pItemView->IsValid() );
  1361. }
  1362. // Otherwise it's a real owned item
  1363. else
  1364. {
  1365. CUtlMap< itemid_t, XUID >::IndexType_t idx = m_mapItems2Owners.Find( uiItemId );
  1366. if ( idx == m_mapItems2Owners.InvalidIndex() )
  1367. return NULL;
  1368. XUID xuidOwner = m_mapItems2Owners.Element( idx );
  1369. if ( !xuidOwner )
  1370. return NULL;
  1371. CCSPlayerInventory *pInv = CSInventoryManager()->GetInventoryForPlayer( CSteamID( xuidOwner ) );
  1372. if ( !pInv )
  1373. return NULL;
  1374. pItemView = pInv->GetInventoryItemByItemID( uiItemId );
  1375. }
  1376. return pItemView;
  1377. }
  1378. public:
  1379. CUtlMap< itemid_t, XUID > m_mapItems2Owners;
  1380. }
  1381. g_ScaleformInventoryImageProviderImpl;
  1382. CEconItemView * CEconItemView::FindOrCreateEconItemViewForItemID( uint64 uiItemId )
  1383. {
  1384. return g_ScaleformInventoryImageProviderImpl.FindOrCreateEconItemViewForItemID( uiItemId );
  1385. }
  1386. #else
  1387. CEconItemView::UtlMapLookupByID_t CEconItemView::s_mapLookupByID;
  1388. #endif // CLIENT_DLL
  1389. //-----------------------------------------------------------------------------
  1390. // Purpose:
  1391. //-----------------------------------------------------------------------------
  1392. void CCSPlayerInventory::ItemHasBeenUpdated( CEconItemView *pItem, bool bUpdateAckFile, bool bWriteAckFile, EInventoryItemEvent eEventType )
  1393. {
  1394. Assert( pItem );
  1395. BaseClass::ItemHasBeenUpdated( pItem, bUpdateAckFile, bWriteAckFile, eEventType );
  1396. CEconItem *pEconItem = pItem->GetSOCData();
  1397. #ifdef CLIENT_DLL
  1398. bool bRequestedGenerateStickerMaterials = false;
  1399. #endif
  1400. for ( equipped_class_t iTeam = 0; iTeam < LOADOUT_COUNT; iTeam++ )
  1401. {
  1402. equipped_slot_t unSlot = pEconItem ? pEconItem->GetEquippedPositionForClass( iTeam ) : INVALID_EQUIPPED_SLOT;
  1403. // unequipped items or items reporting an invalid slot
  1404. for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ )
  1405. {
  1406. if ( unSlot != i && m_LoadoutItems[iTeam][i] == pItem->GetItemID() )
  1407. {
  1408. m_LoadoutItems[iTeam][i] = LOADOUT_SLOT_USE_BASE_ITEM;
  1409. }
  1410. }
  1411. if ( unSlot == INVALID_EQUIPPED_SLOT )
  1412. continue;
  1413. Assert( GetInventoryItemByItemID( pItem->GetItemID() ) );
  1414. itemid_t& pLoadoutItemID = m_LoadoutItems[iTeam][unSlot];
  1415. #ifdef CLIENT_DLL
  1416. /*
  1417. Undoing this -- This causes a bug when trying to equip both slots for a gun. The GC unequips
  1418. the previous guns when handling the normal equip messages so this shouldn't be needed anyway.
  1419. if ( pLoadoutItemID != pItem->GetItemID() )
  1420. {
  1421. // We've got another item that thinks it's in this loadout slot. Move it out.
  1422. CEconItemView *pItemAlreadyInPosition = GetItemInLoadout( iTeam, unSlot );
  1423. if ( pItemAlreadyInPosition )
  1424. {
  1425. // Unequip it.
  1426. pItemAlreadyInPosition->UpdateEquippedState( iTeam, INVALID_EQUIPPED_SLOT );
  1427. InventoryManager()->UpdateInventoryEquippedState( this, pItemAlreadyInPosition->GetItemID(), iTeam, INVALID_EQUIPPED_SLOT );
  1428. }
  1429. }
  1430. */
  1431. if ( InventoryManager()->GetLocalInventory() == this )
  1432. {
  1433. // Any weapons in our loadout should update their materials now!
  1434. // That way there's no hitch when we first buy the item in game!
  1435. pItem->UpdateGeneratedMaterial();
  1436. pItem->GenerateStickerMaterials();
  1437. bRequestedGenerateStickerMaterials = true;
  1438. }
  1439. #endif
  1440. // This may be an invalid slot for the item, but CTFPlayerInventory::InventoryReceived()
  1441. // will have detected that and sent off a request already to move it. The response
  1442. // to that will clear this loadout slot.
  1443. pLoadoutItemID = pItem->GetItemID();
  1444. }
  1445. #ifdef CLIENT_DLL
  1446. if ( pItem->ItemHasAnyStickersApplied() && !bRequestedGenerateStickerMaterials )
  1447. {
  1448. pItem->GenerateStickerMaterials();
  1449. bRequestedGenerateStickerMaterials = true;
  1450. }
  1451. #endif
  1452. #ifdef CLIENT_DLL
  1453. // Assert that this item belongs to this inventory and store the mapping to owner
  1454. CSteamID owner( this->GetOwner().ID() );
  1455. Assert( pItem->GetAccountID() == owner.GetAccountID() );
  1456. g_ScaleformInventoryImageProviderImpl.m_mapItems2Owners.InsertOrReplace( pItem->GetItemID(), owner.ConvertToUint64() );
  1457. // Make sure that the item inventory image is updated no that the item can be found in the mapping
  1458. g_pScaleformUI->InventoryImageUpdate( pItem->GetItemID(), g_pIScaleformInventoryImageProvider );
  1459. #endif
  1460. }
  1461. void CCSPlayerInventory::DefaultEquippedDefinitionHasBeenUpdated( CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinition )
  1462. {
  1463. BaseClass::DefaultEquippedDefinitionHasBeenUpdated( pDefaultEquippedDefinition );
  1464. if ( pDefaultEquippedDefinition->Obj().item_definition() == LOADOUT_SLOT_USE_BASE_ITEM )
  1465. return;
  1466. int unSlot = pDefaultEquippedDefinition->Obj().slot_id();
  1467. if ( unSlot == INVALID_EQUIPPED_SLOT )
  1468. return;
  1469. int nTeam = pDefaultEquippedDefinition->Obj().class_id();
  1470. if ( nTeam < 0 || nTeam >= LOADOUT_COUNT )
  1471. return;
  1472. m_LoadoutItems[ nTeam ][ unSlot ] = LOADOUT_SLOT_USE_BASE_ITEM;
  1473. }
  1474. //-----------------------------------------------------------------------------
  1475. // Purpose:
  1476. //-----------------------------------------------------------------------------
  1477. void CCSPlayerInventory::ItemIsBeingRemoved( CEconItemView *pItem )
  1478. {
  1479. for ( int iTeam = 0; iTeam < LOADOUT_COUNT; iTeam++ )
  1480. {
  1481. if ( pItem->IsEquippedForClass( iTeam ) )
  1482. {
  1483. for ( int iSlot = 0; iSlot < LOADOUT_POSITION_COUNT; iSlot++ )
  1484. {
  1485. if ( m_LoadoutItems[iTeam][iSlot] == pItem->GetItemID() )
  1486. {
  1487. m_LoadoutItems[iTeam][iSlot] = LOADOUT_SLOT_USE_BASE_ITEM;
  1488. }
  1489. }
  1490. }
  1491. }
  1492. }
  1493. bool CCSPlayerInventory::IsMissionRefuseAllowed( void ) const
  1494. {
  1495. #if 1
  1496. return false;
  1497. #else
  1498. CEconGameAccountClient *pGameAccountClient = GetSOCacheGameAccountClient( m_pSOCache );
  1499. if ( !pGameAccountClient )
  1500. return false;
  1501. return ( 1 == pGameAccountClient->Obj().mission_refuse_allowed() );
  1502. #endif
  1503. }