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.

732 lines
24 KiB

  1. //========= Copyright � 1996-2003, Valve LLC, All rights reserved. ============
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "attribute_manager.h"
  8. #include "saverestore.h"
  9. #include "saverestore_utlvector.h"
  10. #include "fmtstr.h"
  11. #include "keyvalues.h"
  12. #include "econ_item_system.h"
  13. #define PROVIDER_PARITY_BITS 6
  14. #define PROVIDER_PARITY_MASK ((1<<PROVIDER_PARITY_BITS)-1)
  15. //==================================================================================================================
  16. // ATTRIBUTE MANAGER SAVE/LOAD & NETWORKING
  17. //===================================================================================================================
  18. BEGIN_DATADESC_NO_BASE( CAttributeManager )
  19. DEFINE_UTLVECTOR( m_Providers, FIELD_EHANDLE ),
  20. DEFINE_FIELD( m_iReapplyProvisionParity, FIELD_INTEGER ),
  21. DEFINE_FIELD( m_hOuter, FIELD_EHANDLE ),
  22. // DEFINE_FIELD( m_bPreventLoopback, FIELD_BOOLEAN ), // Don't need to save
  23. DEFINE_FIELD( m_ProviderType, FIELD_INTEGER ),
  24. END_DATADESC()
  25. BEGIN_DATADESC( CAttributeContainer )
  26. DEFINE_EMBEDDED( m_Item ),
  27. END_DATADESC()
  28. #if defined( TF_DLL ) || defined( CSTRIKE_DLL )
  29. BEGIN_DATADESC( CAttributeContainerPlayer )
  30. END_DATADESC()
  31. #endif
  32. #ifndef CLIENT_DLL
  33. EXTERN_SEND_TABLE( DT_ScriptCreatedItem );
  34. #else
  35. EXTERN_RECV_TABLE( DT_ScriptCreatedItem );
  36. #endif
  37. BEGIN_NETWORK_TABLE_NOBASE( CAttributeManager, DT_AttributeManager )
  38. #ifndef CLIENT_DLL
  39. SendPropEHandle( SENDINFO(m_hOuter) ),
  40. SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
  41. SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
  42. #else
  43. RecvPropEHandle( RECVINFO(m_hOuter) ),
  44. RecvPropInt( RECVINFO(m_ProviderType) ),
  45. RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
  46. #endif
  47. END_NETWORK_TABLE()
  48. BEGIN_NETWORK_TABLE_NOBASE( CAttributeContainer, DT_AttributeContainer )
  49. #ifndef CLIENT_DLL
  50. SendPropEHandle( SENDINFO(m_hOuter) ),
  51. SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
  52. SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
  53. SendPropDataTable(SENDINFO_DT(m_Item), &REFERENCE_SEND_TABLE(DT_ScriptCreatedItem)),
  54. #else
  55. RecvPropEHandle( RECVINFO(m_hOuter) ),
  56. RecvPropInt( RECVINFO(m_ProviderType) ),
  57. RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
  58. RecvPropDataTable(RECVINFO_DT(m_Item), 0, &REFERENCE_RECV_TABLE(DT_ScriptCreatedItem)),
  59. #endif
  60. END_NETWORK_TABLE()
  61. #if defined( TF_DLL ) || defined( CSTRIKE_DLL )
  62. BEGIN_NETWORK_TABLE_NOBASE( CAttributeContainerPlayer, DT_AttributeContainerPlayer )
  63. #ifndef CLIENT_DLL
  64. SendPropEHandle( SENDINFO(m_hOuter) ),
  65. SendPropInt( SENDINFO(m_ProviderType), 4, SPROP_UNSIGNED ),
  66. SendPropInt( SENDINFO(m_iReapplyProvisionParity), PROVIDER_PARITY_BITS, SPROP_UNSIGNED ),
  67. SendPropEHandle( SENDINFO(m_hPlayer) ),
  68. #else
  69. RecvPropEHandle( RECVINFO(m_hOuter) ),
  70. RecvPropInt( RECVINFO(m_ProviderType) ),
  71. RecvPropInt( RECVINFO(m_iReapplyProvisionParity) ),
  72. RecvPropEHandle( RECVINFO( m_hPlayer ) ),
  73. #endif
  74. END_NETWORK_TABLE()
  75. #endif
  76. template< class T > T AttributeConvertFromFloat( float flValue )
  77. {
  78. return static_cast<T>( flValue );
  79. }
  80. template<> float AttributeConvertFromFloat<float>( float flValue )
  81. {
  82. return flValue;
  83. }
  84. template<> int AttributeConvertFromFloat<int>( float flValue )
  85. {
  86. return RoundFloatToInt( flValue );
  87. }
  88. //-----------------------------------------------------------------------------
  89. // All fields in the object are all initialized to 0.
  90. //-----------------------------------------------------------------------------
  91. void *CAttributeManager::operator new( size_t stAllocateBlock )
  92. {
  93. ASSERT_MEMALLOC_WILL_ALIGN( CAttributeManager );
  94. void *pMem = MemAlloc_Alloc( stAllocateBlock );
  95. memset( pMem, 0, stAllocateBlock );
  96. return pMem;
  97. };
  98. void *CAttributeManager::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
  99. {
  100. ASSERT_MEMALLOC_WILL_ALIGN( CAttributeManager );
  101. void *pMem = MemAlloc_Alloc( stAllocateBlock, pFileName, nLine );
  102. memset( pMem, 0, stAllocateBlock );
  103. return pMem;
  104. }
  105. #ifdef CLIENT_DLL
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. //-----------------------------------------------------------------------------
  109. void CAttributeManager::OnPreDataChanged( DataUpdateType_t updateType )
  110. {
  111. m_iOldReapplyProvisionParity = m_iReapplyProvisionParity;
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose:
  115. //-----------------------------------------------------------------------------
  116. void CAttributeManager::OnDataChanged( DataUpdateType_t updateType )
  117. {
  118. if ( m_iReapplyProvisionParity != m_iOldReapplyProvisionParity )
  119. {
  120. // We've changed who we're providing to in some way. Reapply it.
  121. IHasAttributes *pAttribInterface = dynamic_cast<IHasAttributes *>( GetOuter() );
  122. if ( pAttribInterface )
  123. {
  124. pAttribInterface->ReapplyProvision();
  125. }
  126. ClearCache();
  127. m_iOldReapplyProvisionParity = m_iReapplyProvisionParity.Get();
  128. }
  129. }
  130. #endif // CLIENT_DLL
  131. //-----------------------------------------------------------------------------
  132. // Purpose: Call this inside your entity's Spawn()
  133. //-----------------------------------------------------------------------------
  134. void CAttributeManager::InitializeAttributes( CBaseEntity *pEntity )
  135. {
  136. Assert( dynamic_cast<IHasAttributes*>( pEntity ) );
  137. m_hOuter = pEntity;
  138. m_bPreventLoopback = false;
  139. }
  140. //=====================================================================================================
  141. // ATTRIBUTE PROVIDERS
  142. //=====================================================================================================
  143. //-----------------------------------------------------------------------------
  144. // Purpose:
  145. //-----------------------------------------------------------------------------
  146. void CAttributeManager::ProvideTo( CBaseEntity *pProvider )
  147. {
  148. IHasAttributes *pOwnerAttribInterface = dynamic_cast<IHasAttributes *>( pProvider );
  149. if ( pOwnerAttribInterface )
  150. {
  151. if ( CAttributeManager * pAttrMgrForUse = pOwnerAttribInterface->GetAttributeManager() )
  152. pAttrMgrForUse->AddProvider( m_hOuter.Get() );
  153. #ifndef CLIENT_DLL
  154. m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
  155. NetworkStateChanged();
  156. #endif
  157. }
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose:
  161. //-----------------------------------------------------------------------------
  162. void CAttributeManager::StopProvidingTo( CBaseEntity *pProvider )
  163. {
  164. IHasAttributes *pOwnerAttribInterface = dynamic_cast<IHasAttributes *>( pProvider );
  165. if ( pOwnerAttribInterface )
  166. {
  167. if ( CAttributeManager * pAttrMgrForUse = pOwnerAttribInterface->GetAttributeManager() )
  168. pAttrMgrForUse->RemoveProvider( m_hOuter.Get() );
  169. #ifndef CLIENT_DLL
  170. m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
  171. NetworkStateChanged();
  172. #endif
  173. }
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose:
  177. //-----------------------------------------------------------------------------
  178. void CAttributeManager::AddProvider( CBaseEntity *pProvider )
  179. {
  180. // Make sure he's not already in our list, and prevent circular provision
  181. Assert( !IsBeingProvidedToBy(pProvider) );
  182. Assert( !IsProvidingTo(pProvider) );
  183. // Ensure he's allowed to provide
  184. Assert( dynamic_cast<IHasAttributes *>(pProvider) );
  185. m_Providers.AddToTail( pProvider );
  186. ClearCache();
  187. /*
  188. #ifdef CLIENT_DLL
  189. Msg("CLIENT PROVIDER UPDATE: %s now has %d providers:\n", STRING(GetOuter()->GetDebugName()), m_Providers.Count() );
  190. for ( int i = 0; i < m_Providers.Count(); i++ )
  191. {
  192. Msg(" %d: %s\n", i, STRING(m_Providers[i]->GetDebugName()) );
  193. }
  194. #else
  195. Msg("SERVER PROVIDER UPDATE: %s now has %d providers:\n", GetOuter()->GetDebugName(), m_Providers.Count() );
  196. for ( int i = 0; i < m_Providers.Count(); i++ )
  197. {
  198. Msg(" %d: %s\n", i, m_Providers[i]->GetDebugName() );
  199. }
  200. #endif
  201. */
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose:
  205. //-----------------------------------------------------------------------------
  206. void CAttributeManager::RemoveProvider( CBaseEntity *pProvider )
  207. {
  208. m_Providers.FindAndRemove( pProvider );
  209. ClearCache();
  210. /*
  211. #ifdef CLIENT_DLL
  212. Msg("CLIENT PROVIDER UPDATE: %s now has %d providers:\n", STRING(GetOuter()->GetDebugName()), m_Providers.Count() );
  213. for ( int i = 0; i < m_Providers.Count(); i++ )
  214. {
  215. Msg(" %d: %s\n", i, STRING(m_Providers[i]->GetDebugName()) );
  216. }
  217. #else
  218. Msg("SERVER PROVIDER UPDATE: %s now has %d providers:\n", GetOuter()->GetDebugName(), m_Providers.Count() );
  219. for ( int i = 0; i < m_Providers.Count(); i++ )
  220. {
  221. Msg(" %d: %s\n", i, m_Providers[i]->GetDebugName() );
  222. }
  223. #endif
  224. */
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. //-----------------------------------------------------------------------------
  229. void CAttributeManager::ClearCache( void )
  230. {
  231. if ( m_bPreventLoopback )
  232. return;
  233. m_CachedResults.Purge();
  234. m_bPreventLoopback = true;
  235. // Tell all providers relying on me that they need to wipe their cache too
  236. int iCount = m_Providers.Count();
  237. for ( int iHook = 0; iHook < iCount; iHook++ )
  238. {
  239. IHasAttributes *pAttribInterface = dynamic_cast<IHasAttributes *>(m_Providers[iHook].Get());
  240. if ( pAttribInterface )
  241. {
  242. if ( CAttributeManager * pAttrMgrForUse = pAttribInterface->GetAttributeManager() )
  243. pAttrMgrForUse->ClearCache();
  244. }
  245. }
  246. // Tell our owner that he needs to clear his too, in case he has attributes affecting him
  247. IHasAttributes *pMyAttribInterface = dynamic_cast<IHasAttributes *>( m_hOuter.Get().Get() );
  248. if ( pMyAttribInterface )
  249. {
  250. if ( CAttributeManager * pAttrMgrForUse = pMyAttribInterface->GetAttributeManager() )
  251. pAttrMgrForUse->ClearCache();
  252. }
  253. m_bPreventLoopback = false;
  254. #ifndef CLIENT_DLL
  255. // Force out client to clear their cache as well
  256. m_iReapplyProvisionParity = (m_iReapplyProvisionParity + 1) & PROVIDER_PARITY_MASK;
  257. NetworkStateChanged();
  258. #endif
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Purpose:
  262. //-----------------------------------------------------------------------------
  263. CBaseEntity *CAttributeManager::GetProvider( int iIndex )
  264. {
  265. Assert( iIndex >= 0 && iIndex < m_Providers.Count() );
  266. return m_Providers[iIndex];
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose: Return true if this entity is providing attributes to the specified entity
  270. //-----------------------------------------------------------------------------
  271. bool CAttributeManager::IsProvidingTo( CBaseEntity *pEntity )
  272. {
  273. IHasAttributes *pAttribInterface = dynamic_cast<IHasAttributes *>(pEntity);
  274. if ( pAttribInterface )
  275. {
  276. if ( CAttributeManager * pAttrMgrForUse = pAttribInterface->GetAttributeManager() )
  277. if ( pAttrMgrForUse->IsBeingProvidedToBy( GetOuter() ) )
  278. return true;
  279. }
  280. return false;
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose: Return true if this entity is being provided attributes by the specified entity
  284. //-----------------------------------------------------------------------------
  285. bool CAttributeManager::IsBeingProvidedToBy( CBaseEntity *pEntity )
  286. {
  287. return ( m_Providers.Find( pEntity ) != m_Providers.InvalidIndex() );
  288. }
  289. //=====================================================================================================
  290. // ATTRIBUTE HOOKS
  291. //=====================================================================================================
  292. //-----------------------------------------------------------------------------
  293. // Purpose: Wrapper that checks to see if we've already got the result in our cache
  294. //-----------------------------------------------------------------------------
  295. float CAttributeManager::ApplyAttributeFloatWrapper( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
  296. {
  297. int iCount = m_CachedResults.Count();
  298. for ( int i = iCount-1; i >= 0; i-- )
  299. {
  300. if ( m_CachedResults[i].iAttribHook == iszAttribHook )
  301. {
  302. if ( m_CachedResults[i].flIn == flValue )
  303. return m_CachedResults[i].flOut;
  304. // We've got a cached result for a different flIn value. Remove the cached result to
  305. // prevent stacking up entries for different requests (i.e. crit chance)
  306. m_CachedResults.Remove(i);
  307. break;
  308. }
  309. }
  310. // Wasn't in cache. Do the work.
  311. float flResult = ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
  312. // Add it to our cache
  313. int iIndex = m_CachedResults.AddToTail();
  314. m_CachedResults[iIndex].flIn = flValue;
  315. m_CachedResults[iIndex].flOut = flResult;
  316. m_CachedResults[iIndex].iAttribHook = iszAttribHook;
  317. return flResult;
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Purpose:
  321. //-----------------------------------------------------------------------------
  322. float CAttributeManager::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
  323. {
  324. if ( m_bPreventLoopback || !GetOuter() )
  325. return flValue;
  326. // We need to prevent loopback between two items both providing to the same entity.
  327. m_bPreventLoopback = true;
  328. // See if we have any providers. If we do, tell them to apply.
  329. int iCount = m_Providers.Count();
  330. for ( int iHook = 0; iHook < iCount; iHook++ )
  331. {
  332. if ( m_Providers[iHook].Get() == pInitiator )
  333. continue;
  334. // Don't allow weapons to provide to other weapons being carried by the same person
  335. IHasAttributes *pAttribInterface = dynamic_cast<IHasAttributes *>(m_Providers[iHook].Get());
  336. if ( pInitiator && pAttribInterface->GetAttributeManager() &&
  337. pAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON )
  338. {
  339. IHasAttributes *pInitiatorAttribInterface = dynamic_cast<IHasAttributes *>(pInitiator);
  340. if ( pInitiatorAttribInterface->GetAttributeManager() &&
  341. pInitiatorAttribInterface->GetAttributeManager()->GetProviderType() == PROVIDER_WEAPON )
  342. continue;
  343. }
  344. if ( CAttributeManager *pAttrMgrForUse = pAttribInterface->GetAttributeManager() )
  345. flValue = pAttrMgrForUse->ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
  346. }
  347. // Then see if our owner has any attributes he wants to apply as well.
  348. // i.e. An aura is providing attributes to this weapon's carrier.
  349. IHasAttributes *pMyAttribInterface = dynamic_cast<IHasAttributes *>( m_hOuter.Get().Get() );
  350. if ( pMyAttribInterface->GetAttributeOwner() )
  351. {
  352. IHasAttributes *pOwnerAttribInterface = dynamic_cast<IHasAttributes *>( pMyAttribInterface->GetAttributeOwner() );
  353. if ( pOwnerAttribInterface )
  354. {
  355. if ( CAttributeManager * pAttrMgrForUse = pOwnerAttribInterface->GetAttributeManager() )
  356. flValue = pAttrMgrForUse->ApplyAttributeFloat( flValue, pInitiator, iszAttribHook, pItemList );
  357. }
  358. }
  359. m_bPreventLoopback = false;
  360. return flValue;
  361. }
  362. //=====================================================================================================
  363. // ATTRIBUTE CONTAINER
  364. //=====================================================================================================
  365. //-----------------------------------------------------------------------------
  366. // Purpose: Call this inside your entity's Spawn()
  367. //-----------------------------------------------------------------------------
  368. void CAttributeContainer::InitializeAttributes( CBaseEntity *pEntity )
  369. {
  370. BaseClass::InitializeAttributes( pEntity );
  371. #ifndef CLIENT_DLL
  372. /*
  373. if ( !m_Item.IsValid() )
  374. {
  375. Warning("Item '%s' not setup correctly. Attempting to create attributes on an unitialized item.\n", m_hOuter.Get()->GetDebugName() );
  376. }
  377. */
  378. #endif
  379. m_Item.GetAttributeList()->SetManager( this );
  380. ClearCache();
  381. }
  382. static void ApplyAttribute( const CEconItemAttributeDefinition *pAttributeDef, float& flValue, const float flValueModifier )
  383. {
  384. Assert( pAttributeDef );
  385. Assert( pAttributeDef->GetAttributeType() );
  386. AssertMsg1( pAttributeDef->GetAttributeType()->BSupportsGameplayModificationAndNetworking(), "Attempt to hook the value of attribute '%s' which doesn't support hooking! Pull the value of the attribute directly using FindAttribute()!", pAttributeDef->GetDefinitionName() );
  387. const int iAttrDescFormat = pAttributeDef->GetDescriptionFormat();
  388. switch ( iAttrDescFormat )
  389. {
  390. case ATTDESCFORM_VALUE_IS_PERCENTAGE:
  391. case ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE:
  392. {
  393. flValue *= flValueModifier;
  394. }
  395. break;
  396. case ATTDESCFORM_VALUE_IS_COLOR:
  397. case ATTDESCFORM_VALUE_IS_ADDITIVE:
  398. case ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE:
  399. case ATTDESCFORM_VALUE_IS_PARTICLE_INDEX:
  400. {
  401. flValue += flValueModifier;
  402. }
  403. break;
  404. case ATTDESCFORM_VALUE_IS_REPLACE:
  405. {
  406. flValue = flValueModifier;
  407. }
  408. break;
  409. case ATTDESCFORM_VALUE_IS_OR:
  410. {
  411. int iTmp = flValue;
  412. iTmp |= (int)flValueModifier;
  413. flValue = iTmp;
  414. }
  415. break;
  416. case ATTDESCFORM_VALUE_IS_GAME_TIME:
  417. case ATTDESCFORM_VALUE_IS_DATE:
  418. Assert( !"Attempt to apply date attribute in ApplyAttribute()." ); // No-one should be hooking date descriptions
  419. break;
  420. default:
  421. // Unknown value format.
  422. AssertMsg1( false, "Unknown attribute value type %i in ApplyAttribute().", iAttrDescFormat );
  423. break;
  424. }
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Purpose: Given two attributes, return a collated value.
  428. //-----------------------------------------------------------------------------
  429. float CollateAttributeValues( const CEconItemAttribute *pAttrib1, const CEconItemAttribute *pAttrib2 )
  430. {
  431. // We can only collate attributes of matching definitions
  432. Assert( !Q_stricmp( pAttrib1->GetStaticData()->GetAttributeClass(), pAttrib2->GetStaticData()->GetAttributeClass() ) );
  433. const CEconItemAttributeDefinition *pDef = pAttrib1->GetStaticData();
  434. const int iAttrDescFormat = pDef->GetDescriptionFormat();
  435. float flValue = 0;
  436. switch ( iAttrDescFormat )
  437. {
  438. case ATTDESCFORM_VALUE_IS_PERCENTAGE:
  439. case ATTDESCFORM_VALUE_IS_INVERTED_PERCENTAGE:
  440. {
  441. flValue = 1.0;
  442. }
  443. break;
  444. case ATTDESCFORM_VALUE_IS_COLOR:
  445. case ATTDESCFORM_VALUE_IS_ADDITIVE:
  446. case ATTDESCFORM_VALUE_IS_ADDITIVE_PERCENTAGE:
  447. case ATTDESCFORM_VALUE_IS_OR:
  448. case ATTDESCFORM_VALUE_IS_REPLACE:
  449. {
  450. flValue = 0;
  451. }
  452. break;
  453. case ATTDESCFORM_VALUE_IS_DATE:
  454. Assert( !"Attempt to apply date attribute in ApplyAttribute()." ); // No-one should be hooking date descriptions
  455. break;
  456. default:
  457. // Unknown value format.
  458. AssertMsg1( false, "Unknown attribute value type %i in ApplyAttribute().", iAttrDescFormat );
  459. break;
  460. }
  461. ApplyAttribute( pDef, flValue, pAttrib1->GetValue() );
  462. ApplyAttribute( pDef, flValue, pAttrib2->GetValue() );
  463. return flValue;
  464. }
  465. //-----------------------------------------------------------------------------
  466. // Purpose:
  467. //-----------------------------------------------------------------------------
  468. class CEconItemAttributeIterator_ApplyAttributeFloat : public IEconItemAttributeIterator
  469. {
  470. public:
  471. CEconItemAttributeIterator_ApplyAttributeFloat( CBaseEntity *pOuter, float flInitialValue, string_t iszAttribHook, CUtlVector<CBaseEntity *> *pItemList )
  472. : m_pOuter( pOuter )
  473. , m_flValue( flInitialValue )
  474. , m_iszAttribHook( iszAttribHook )
  475. , m_pItemList( pItemList )
  476. {
  477. Assert( pOuter );
  478. }
  479. virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, attrib_value_t value )
  480. {
  481. COMPILE_TIME_ASSERT( sizeof( value ) == sizeof( float ) );
  482. Assert( pAttrDef );
  483. if ( pAttrDef->GetCachedClass() != m_iszAttribHook )
  484. return true;
  485. if ( m_pItemList && !m_pItemList->HasElement( m_pOuter ) )
  486. {
  487. m_pItemList->AddToTail( m_pOuter );
  488. }
  489. ApplyAttribute( pAttrDef, m_flValue, *reinterpret_cast<float *>( &value ) );
  490. // We assume that each attribute can only be in the attribute list for a single item once, but we're
  491. // iterating over attribute *classes* here, not unique attribute types, so we carry on looking.
  492. return true;
  493. }
  494. virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, float value )
  495. {
  496. Assert( pAttrDef );
  497. if ( pAttrDef->GetCachedClass() != m_iszAttribHook )
  498. return true;
  499. if ( m_pItemList && !m_pItemList->HasElement( m_pOuter ) )
  500. {
  501. m_pItemList->AddToTail( m_pOuter );
  502. }
  503. ApplyAttribute( pAttrDef, m_flValue, value );
  504. // We assume that each attribute can only be in the attribute list for a single item once, but we're
  505. // iterating over attribute *classes* here, not unique attribute types, so we carry on looking.
  506. return true;
  507. }
  508. virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const CAttribute_String& value )
  509. {
  510. // We can't possibly process an attribute of this type!
  511. Assert( pAttrDef );
  512. Assert( pAttrDef->GetCachedClass() != m_iszAttribHook );
  513. return true;
  514. }
  515. virtual bool OnIterateAttributeValue( const CEconItemAttributeDefinition *pAttrDef, const Vector& value )
  516. {
  517. // We can't possibly process an attribute of this type!
  518. Assert( pAttrDef );
  519. Assert( pAttrDef->GetCachedClass() != m_iszAttribHook );
  520. return true;
  521. }
  522. float GetResultValue() const
  523. {
  524. return m_flValue;
  525. }
  526. private:
  527. CBaseEntity *m_pOuter;
  528. float m_flValue;
  529. string_t m_iszAttribHook;
  530. CUtlVector<CBaseEntity *> *m_pItemList;
  531. };
  532. //-----------------------------------------------------------------------------
  533. // Purpose:
  534. //-----------------------------------------------------------------------------
  535. float CAttributeContainer::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
  536. {
  537. if ( m_bPreventLoopback || !GetOuter() )
  538. return flValue;
  539. // We need to prevent loopback between two items both providing to the same entity.
  540. m_bPreventLoopback = true;
  541. // ...
  542. CEconItemAttributeIterator_ApplyAttributeFloat it( GetOuter(), flValue, iszAttribHook, pItemList );
  543. m_Item.IterateAttributes( &it );
  544. m_bPreventLoopback = false;
  545. return BaseClass::ApplyAttributeFloat( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
  546. }
  547. #if defined( TF_DLL ) || defined( CSTRIKE_DLL )
  548. //-----------------------------------------------------------------------------
  549. // Purpose:
  550. //-----------------------------------------------------------------------------
  551. void CAttributeContainerPlayer::InitializeAttributes( CBaseEntity *pEntity )
  552. {
  553. BaseClass::InitializeAttributes( pEntity );
  554. ClearCache();
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Purpose:
  558. //-----------------------------------------------------------------------------
  559. float CAttributeContainerPlayer::ApplyAttributeFloat( float flValue, CBaseEntity *pInitiator, string_t iszAttribHook, CUtlVector<CBaseEntity*> *pItemList )
  560. {
  561. if ( m_bPreventLoopback || !GetOuter() )
  562. return flValue;
  563. m_bPreventLoopback = true;
  564. #ifdef DEBUG
  565. int iFoundAttributeCount = 0;
  566. #endif // DEBUG
  567. CEconItemAttributeIterator_ApplyAttributeFloat it( GetOuter(), flValue, iszAttribHook, pItemList );
  568. #if defined( USE_PLAYER_ATTRIBUTE_MANAGER )
  569. CBasePlayer *pPlayer = GetPlayer();
  570. if ( pPlayer )
  571. {
  572. pPlayer->m_AttributeList.IterateAttributes( &it );
  573. // Apply all the attributes within this manager
  574. int iAttributes = pPlayer->m_AttributeList.GetNumAttributes();
  575. for ( int i = 0; i < iAttributes; i++ )
  576. {
  577. CEconItemAttribute *pAttribute = pPlayer->m_AttributeList.GetAttribute(i);
  578. CEconItemAttributeDefinition *pData = pAttribute->GetStaticData();
  579. // The first time we try to compare to an attribute, we alloc this for faster future lookup
  580. if ( pData->GetCachedClass() == iszAttribHook )
  581. {
  582. // If we are keep track (ie. pItemList != NULL), then put the item in the list.
  583. if ( pItemList )
  584. {
  585. if ( pItemList->Find( GetOuter() ) == -1 )
  586. {
  587. pItemList->AddToTail( GetOuter() );
  588. }
  589. }
  590. ApplyAttribute( pData, flValue, pAttribute->GetValue() );
  591. #ifdef DEBUG
  592. iFoundAttributeCount++;
  593. #endif // DEBUG
  594. }
  595. }
  596. }
  597. #endif //#if defined( USE_PLAYER_ATTRIBUTE_MANAGER )
  598. #ifdef DEBUG
  599. // If we didn't find any attributes on this object, loop through all the attributes in our schema to find
  600. // out whether this attribute even exists so we can spew a warning if it doesn't.
  601. if ( iFoundAttributeCount == 0 )
  602. {
  603. const CEconItemSchema::EconAttrDefsContainer_t & mapAttrDefs = ItemSystem()->GetItemSchema()->GetAttributeDefinitionContainer();
  604. FOR_EACH_VEC( mapAttrDefs, i )
  605. {
  606. if ( mapAttrDefs[i] && ( mapAttrDefs[i]->GetCachedClass() == iszAttribHook ) )
  607. {
  608. iFoundAttributeCount++;
  609. break;
  610. }
  611. }
  612. }
  613. AssertMsg1( iFoundAttributeCount != 0, "Attempt to apply unknown attribute '%s'.", STRING( iszAttribHook ) );
  614. #endif // DEBUG
  615. m_bPreventLoopback = false;
  616. return BaseClass::ApplyAttributeFloat( it.GetResultValue(), pInitiator, iszAttribHook, pItemList );
  617. }
  618. #endif