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.

1706 lines
52 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "econ_entity_creation.h"
  8. #include "vgui/ILocalize.h"
  9. #include "tier3/tier3.h"
  10. #if defined( CLIENT_DLL )
  11. #define UTIL_VarArgs VarArgs
  12. #include "econ_item_inventory.h"
  13. #include "model_types.h"
  14. #include "eventlist.h"
  15. #include "networkstringtable_clientdll.h"
  16. #if defined(CSTRIKE_CLIENT_DLL)
  17. #include "cstrike15_item_inventory.h"
  18. #endif
  19. #if defined(TF_CLIENT_DLL)
  20. #include "c_tf_player.h"
  21. #include "tf_gamerules.h"
  22. #include "c_playerresource.h"
  23. #endif
  24. #if defined(DOTA_DLL) && defined( GAME_DLL )
  25. #include "dota_npc_base.h"
  26. #endif
  27. #if defined(DOTA_DLL) && defined( CLIENT_DLL )
  28. #include "c_dota_npc_base.h"
  29. #endif
  30. extern INetworkStringTable *g_StringTableDynamicModels;
  31. extern CUtlMap<int, int> g_DynamicModelStringRemap;
  32. #if defined(DOTA_DLL)
  33. #include "dota_particle_manager.h"
  34. #endif
  35. extern INetworkStringTable *g_StringTableDynamicModels;
  36. extern CUtlMap<int, int> g_DynamicModelStringRemap;
  37. #else // defined( CLIENT_DLL )
  38. #include "activitylist.h"
  39. #if defined(TF_DLL)
  40. #include "tf_player.h"
  41. #endif
  42. #endif // defined( CLIENT_DLL )
  43. // memdbgon must be the last include file in a .cpp file!!!
  44. #include "tier0/memdbgon.h"
  45. IMPLEMENT_NETWORKCLASS_ALIASED( EconEntity, DT_EconEntity )
  46. IMPLEMENT_NETWORKCLASS_ALIASED( BaseAttributableItem, DT_BaseAttributableItem )
  47. #if defined( CLIENT_DLL )
  48. bool ParseItemKeyvalue( void *pObject, typedescription_t *pFields, int iNumFields, const char *szKeyName, const char *szValue );
  49. #endif
  50. #if defined(_DEBUG)
  51. extern ConVar item_debug;
  52. extern ConVar item_debug_validation;
  53. #endif
  54. #define NUM_FALLBACK_STATTRAK_BITS 20
  55. #define INVALID_STATTRAK_VALUE int( uint32(~0) >> (sizeof(uint32)*8-NUM_FALLBACK_STATTRAK_BITS) )
  56. inline bool IsValidStatTrakValue( int iValue )
  57. {
  58. return ( iValue >= 0 ) && ( iValue < INVALID_STATTRAK_VALUE );
  59. }
  60. #if !defined( CLIENT_DLL )
  61. #define DEFINE_ECON_ENTITY_NETWORK_TABLE() \
  62. SendPropDataTable( SENDINFO_DT( m_AttributeManager ), &REFERENCE_SEND_TABLE(DT_AttributeContainer) ), \
  63. SendPropInt( SENDINFO( m_OriginalOwnerXuidLow ) ), \
  64. SendPropInt( SENDINFO( m_OriginalOwnerXuidHigh ) ), \
  65. SendPropInt( SENDINFO( m_nFallbackPaintKit ), 16, SPROP_UNSIGNED ), \
  66. SendPropInt( SENDINFO( m_nFallbackSeed ), 10, SPROP_UNSIGNED ), \
  67. SendPropFloat( SENDINFO( m_flFallbackWear ), 8, SPROP_NOSCALE, 0.0f, 1.0f ), \
  68. SendPropInt( SENDINFO( m_nFallbackStatTrak ), NUM_FALLBACK_STATTRAK_BITS ),
  69. #else
  70. #define DEFINE_ECON_ENTITY_NETWORK_TABLE() \
  71. RecvPropDataTable( RECVINFO_DT( m_AttributeManager ), 0, &REFERENCE_RECV_TABLE(DT_AttributeContainer) ), \
  72. RecvPropInt( RECVINFO( m_OriginalOwnerXuidLow ) ), \
  73. RecvPropInt( RECVINFO( m_OriginalOwnerXuidHigh ) ), \
  74. RecvPropInt( RECVINFO( m_nFallbackPaintKit ) ), \
  75. RecvPropInt( RECVINFO( m_nFallbackSeed ) ), \
  76. RecvPropFloat( RECVINFO( m_flFallbackWear ) ), \
  77. RecvPropInt( RECVINFO( m_nFallbackStatTrak ) ),
  78. #endif // CLIENT_DLL
  79. BEGIN_NETWORK_TABLE( CEconEntity , DT_EconEntity )
  80. DEFINE_ECON_ENTITY_NETWORK_TABLE()
  81. END_NETWORK_TABLE()
  82. BEGIN_DATADESC( CEconEntity )
  83. END_DATADESC()
  84. //
  85. // Duplicating CEconEntity's network table and data description for backwards compat with demos.
  86. // NOTE: NOTE_RENAMED_RECVTABLE() will not work with this class.
  87. //
  88. BEGIN_NETWORK_TABLE( CBaseAttributableItem, DT_BaseAttributableItem )
  89. DEFINE_ECON_ENTITY_NETWORK_TABLE()
  90. END_NETWORK_TABLE()
  91. BEGIN_DATADESC( CBaseAttributableItem )
  92. END_DATADESC()
  93. #ifdef TF_CLIENT_DLL
  94. extern ConVar cl_flipviewmodels;
  95. #endif
  96. #ifdef CLIENT_DLL
  97. //-----------------------------------------------------------------------------
  98. // Purpose:
  99. //-----------------------------------------------------------------------------
  100. void DrawEconEntityAttachedModels( CBaseAnimating *pEnt, CEconEntity *pAttachedModelSource, const ClientModelRenderInfo_t *pInfo, int iMatchDisplayFlags )
  101. {
  102. #ifndef DOTA_DLL
  103. if ( !pEnt || !pAttachedModelSource || !pInfo )
  104. return;
  105. // Draw our attached models as well
  106. for ( int i = 0; i < pAttachedModelSource->m_vecAttachedModels.Count(); i++ )
  107. {
  108. const CEconEntity::AttachedModelData_t& attachedModel = pAttachedModelSource->m_vecAttachedModels[i];
  109. if ( attachedModel.m_pModel && (attachedModel.m_iModelDisplayFlags & iMatchDisplayFlags) )
  110. {
  111. ClientModelRenderInfo_t infoAttached = *pInfo;
  112. infoAttached.pRenderable = pEnt;
  113. infoAttached.instance = MODEL_INSTANCE_INVALID;
  114. infoAttached.entity_index = pEnt->index;
  115. infoAttached.pModel = attachedModel.m_pModel;
  116. infoAttached.pModelToWorld = &infoAttached.modelToWorld;
  117. // Turns the origin + angles into a matrix
  118. AngleMatrix( infoAttached.angles, infoAttached.origin, infoAttached.modelToWorld );
  119. //DrawModelState_t state;
  120. //matrix3x4_t *pBoneToWorld;
  121. //bool bMarkAsDrawn = modelrender->DrawModelSetup( infoAttached, &state, NULL, &pBoneToWorld );
  122. //pEnt->DoInternalDrawModel( &infoAttached, ( bMarkAsDrawn && ( infoAttached.flags & STUDIO_RENDER ) ) ? &state : NULL, pBoneToWorld );
  123. }
  124. }
  125. #endif
  126. }
  127. #endif // CLIENT_DLL
  128. //-----------------------------------------------------------------------------
  129. // Purpose:
  130. //-----------------------------------------------------------------------------
  131. CEconEntity::CEconEntity()
  132. {
  133. // Inform base entity system that we can deal with dynamic models
  134. // EnableDynamicModels();
  135. #ifdef GAME_DLL
  136. m_iOldOwnerClass = 0;
  137. #endif
  138. #ifdef CLIENT_DLL
  139. m_flFlexDelayTime = 0.0f;
  140. m_flFlexDelayedWeight = NULL;
  141. m_iNumOwnerValidationRetries = 0;
  142. m_bAttributesInitialized = false;
  143. #endif
  144. m_OriginalOwnerXuidLow = 0;
  145. m_OriginalOwnerXuidHigh = 0;
  146. m_nFallbackPaintKit = 0;
  147. m_nFallbackSeed = 0;
  148. m_flFallbackWear = 0;
  149. m_nFallbackStatTrak = -1;
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. //-----------------------------------------------------------------------------
  154. CEconEntity::~CEconEntity()
  155. {
  156. #ifdef CLIENT_DLL
  157. SetParticleSystemsVisible( false );
  158. delete [] m_flFlexDelayedWeight;
  159. #endif
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Purpose:
  163. //-----------------------------------------------------------------------------
  164. CStudioHdr * CEconEntity::OnNewModel()
  165. {
  166. CStudioHdr* hdr = BaseClass::OnNewModel();
  167. #ifdef GAME_DLL
  168. // Adjust class-specific bodygroup after model load if we have a model and a class
  169. if ( hdr && m_iOldOwnerClass > 0 )
  170. {
  171. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  172. if ( pItem && pItem->IsValid() && pItem->GetStaticData()->UsesPerClassBodygroups() )
  173. {
  174. // Classes start at 1, bodygroups at 0
  175. SetBodygroup( 1, m_iOldOwnerClass - 1 );
  176. }
  177. }
  178. #endif
  179. #ifdef TF_CLIENT_DLL
  180. // If we're carried by a player, let him know he should recalc his bodygroups.
  181. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  182. if ( pPlayer )
  183. {
  184. pPlayer->SetBodygroupsDirty();
  185. }
  186. // allocate room for delayed flex weights
  187. delete [] m_flFlexDelayedWeight;
  188. if ( hdr && hdr->numflexcontrollers() )
  189. {
  190. m_flFlexDelayedWeight = new float[ hdr->numflexcontrollers() ];
  191. memset( m_flFlexDelayedWeight, 0, sizeof( float ) * hdr->numflexdesc() );
  192. C_BaseFlex::LinkToGlobalFlexControllers( hdr );
  193. }
  194. #endif // TF_CLIENT_DLL
  195. return hdr;
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose:
  199. //-----------------------------------------------------------------------------
  200. void CEconEntity::InitializeAttributes( void )
  201. {
  202. m_AttributeManager.InitializeAttributes( this );
  203. m_AttributeManager.SetProviderType( PROVIDER_WEAPON );
  204. CEconItemView *pEconItemView = m_AttributeManager.GetItem();
  205. #ifdef CLIENT_DLL
  206. m_bAttributesInitialized = true;
  207. bool bFoundSOData = false;
  208. CSteamID steamID = GetOriginalOwnerXuid();
  209. CPlayerInventory *pInventory = CSInventoryManager()->GetInventoryForPlayer( steamID );
  210. if ( pInventory )
  211. {
  212. CEconItem *pItem = pInventory->GetSOCDataForItem( pEconItemView->GetItemID() );
  213. if ( pItem )
  214. {
  215. bFoundSOData = true;
  216. // All econ entities for gameplay need to generate a material
  217. pEconItemView->UpdateGeneratedMaterial();
  218. // Generate sticker materials now
  219. pEconItemView->GenerateStickerMaterials();
  220. }
  221. }
  222. if ( !bFoundSOData && pEconItemView->GetItemID() > 0 )
  223. {
  224. // The SO Data for this item hasn't been retrieved yet!
  225. // This is the old obsolete fallback for demos
  226. if ( m_nFallbackPaintKit > 0 )
  227. {
  228. pEconItemView->SetOrAddAttributeValueByName( "set item texture prefab", m_nFallbackPaintKit );
  229. }
  230. if ( m_nFallbackSeed > 0 )
  231. {
  232. pEconItemView->SetOrAddAttributeValueByName( "set item texture seed", m_nFallbackSeed );
  233. }
  234. if ( m_flFallbackWear > 0.0f )
  235. {
  236. pEconItemView->SetOrAddAttributeValueByName( "set item texture wear", m_flFallbackWear );
  237. }
  238. if ( IsValidStatTrakValue( m_nFallbackStatTrak ) )
  239. {
  240. int nFallbackStatTrakInt = m_nFallbackStatTrak;
  241. float flFallbackStatTrakHack = *reinterpret_cast<float*>( ( char * ) &nFallbackStatTrakInt );
  242. pEconItemView->SetOrAddAttributeValueByName( "kill eater", flFallbackStatTrakHack );
  243. pEconItemView->SetOrAddAttributeValueByName( "kill eater score type", 0 );
  244. pEconItemView->m_bKillEaterTypesCached = false;
  245. }
  246. // Attributes could have also been networked through the new fallback system m_NetworkedDynamicAttributesForDemos
  247. if ( pEconItemView->GetCustomPaintKit() != 0 /*|| pEconItemView->GetCustomCharacterPaintKit() != 0*/ )
  248. {
  249. // All econ entities for gameplay need to generate a material
  250. pEconItemView->UpdateGeneratedMaterial();
  251. InventoryManager()->InsertMaterialGenerationJob( m_AttributeManager.GetItem() );
  252. }
  253. // Generate sticker materials now
  254. pEconItemView->GenerateStickerMaterials();
  255. }
  256. #else
  257. pEconItemView->InitNetworkedDynamicAttributesForDemos();
  258. // Hack: String attributes don't fit in networked attribute lists. To get the custom name to clients
  259. // we use a separate network string for now... if this happens often we can rework it into a system.
  260. pEconItemView->UpdateNetworkedCustomName();
  261. #endif //#ifdef CLIENT_DLL
  262. }
  263. uint64 CEconEntity::GetOriginalOwnerXuid( void ) const
  264. {
  265. #ifdef CLIENT_DLL
  266. if ( CDemoPlaybackParameters_t const *pPlaybackParams = engine->GetDemoPlaybackParameters() )
  267. {
  268. if ( pPlaybackParams->m_bAnonymousPlayerIdentity )
  269. return 0ull; // force an anonymous weapon owner when watching Overwatch
  270. }
  271. #endif
  272. return ( uint64( m_OriginalOwnerXuidHigh ) << 32 ) | uint64( m_OriginalOwnerXuidLow );
  273. }
  274. //-----------------------------------------------------------------------------
  275. // Purpose:
  276. //-----------------------------------------------------------------------------
  277. void CEconEntity::DebugDescribe( void )
  278. {
  279. CEconItemView *pScriptItem = GetAttributeContainer()->GetItem();
  280. Msg("============================================\n");
  281. char tempstr[1024];
  282. // FIXME: ILocalize::ConvertUnicodeToANSI( pScriptItem->GetItemName(), tempstr, sizeof(tempstr) );
  283. const char *pszQualityString = EconQuality_GetQualityString( (EEconItemQuality)pScriptItem->GetItemQuality() );
  284. Msg("%s \"%s\" (level %d)\n", pszQualityString ? pszQualityString : "[unknown]", tempstr, pScriptItem->GetItemLevel() );
  285. // FIXME: ILocalize::ConvertUnicodeToANSI( pScriptItem->GetAttributeDescription(), tempstr, sizeof(tempstr) );
  286. Msg("%s", tempstr );
  287. Msg("\n============================================\n");
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Purpose:
  291. //-----------------------------------------------------------------------------
  292. void CEconEntity::UpdateOnRemove( void )
  293. {
  294. SetOwnerEntity( NULL );
  295. ReapplyProvision();
  296. #ifdef CLIENT_DLL
  297. if ( m_hViewmodelAttachment )
  298. {
  299. m_hViewmodelAttachment->Remove();
  300. }
  301. #endif
  302. BaseClass::UpdateOnRemove();
  303. }
  304. //-----------------------------------------------------------------------------
  305. // Purpose:
  306. //-----------------------------------------------------------------------------
  307. void CEconEntity::ReapplyProvision( void )
  308. {
  309. #ifdef GAME_DLL
  310. UpdateModelToClass();
  311. #endif //#ifdef GAME_DLL
  312. CBaseEntity *pNewOwner = GetOwnerEntity();
  313. if ( pNewOwner == m_hOldProvidee.Get() )
  314. return;
  315. // Remove ourselves from the old providee's list
  316. if ( m_hOldProvidee.Get() && GetAttributeManager() )
  317. {
  318. GetAttributeManager()->StopProvidingTo( m_hOldProvidee.Get() );
  319. }
  320. // Add ourselves to our new owner's provider list
  321. if ( pNewOwner && GetAttributeManager() )
  322. {
  323. GetAttributeManager()->ProvideTo( pNewOwner );
  324. }
  325. m_hOldProvidee = pNewOwner;
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Purpose:
  329. //-----------------------------------------------------------------------------
  330. Activity CEconEntity::TranslateViewmodelHandActivity( Activity actBase )
  331. {
  332. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  333. if ( pItem && pItem->IsValid() )
  334. {
  335. const GameItemDefinition_t *pStaticData = pItem->GetStaticData();
  336. if ( pStaticData && pStaticData->ShouldAttachToHands() )
  337. {
  338. return TranslateViewmodelHandActivityInternal(actBase);
  339. }
  340. }
  341. return actBase;
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose:
  345. //-----------------------------------------------------------------------------
  346. static int GetCustomParticleEffectId( CEconEntity *pEconEntity )
  347. {
  348. Assert( pEconEntity );
  349. Assert( pEconEntity->GetAttributeContainer() );
  350. Assert( pEconEntity->GetAttributeManager() == pEconEntity->GetAttributeContainer() );
  351. CEconItemView *pEconItemView = pEconEntity->GetAttributeContainer()->GetItem();
  352. int iCustomParticleEffect = 0;
  353. CALL_ATTRIB_HOOK_INT_ON_OTHER( pEconEntity, iCustomParticleEffect, set_attached_particle );
  354. if ( pEconItemView )
  355. {
  356. if ( iCustomParticleEffect == 0 )
  357. {
  358. iCustomParticleEffect = pEconItemView->GetQualityParticleType();
  359. }
  360. if ( iCustomParticleEffect == 0 )
  361. {
  362. static CSchemaAttributeDefHandle pAttrDef_SetAttachedParticle( "attach particle effect" );
  363. float flCustomParticleEffect;
  364. if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pEconItemView, pAttrDef_SetAttachedParticle, &flCustomParticleEffect ) )
  365. {
  366. iCustomParticleEffect = flCustomParticleEffect;
  367. }
  368. }
  369. }
  370. return iCustomParticleEffect;
  371. }
  372. #if !defined( CLIENT_DLL )
  373. //-----------------------------------------------------------------------------
  374. // Purpose:
  375. //-----------------------------------------------------------------------------
  376. void CEconEntity::OnOwnerClassChange( void )
  377. {
  378. #ifdef TF_DLL
  379. CTFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  380. if ( pPlayer && pPlayer->GetPlayerClass()->GetClassIndex() != m_iOldOwnerClass )
  381. {
  382. UpdateModelToClass();
  383. }
  384. #endif
  385. }
  386. //-----------------------------------------------------------------------------
  387. // Purpose:
  388. //-----------------------------------------------------------------------------
  389. int CEconEntity::CalculateVisibleClassFor( CBaseCombatCharacter *pPlayer )
  390. {
  391. #ifdef TF_DLL
  392. CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
  393. return (pTFPlayer ? pTFPlayer->GetPlayerClass()->GetClassIndex() : 0);
  394. #else
  395. return 0;
  396. #endif
  397. }
  398. //-----------------------------------------------------------------------------
  399. int CEconEntity::ShouldTransmit( const CCheckTransmitInfo *pInfo )
  400. {
  401. int iReturn = BaseClass::ShouldTransmit( pInfo );
  402. // TODO
  403. // CBaseEntity *pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
  404. //
  405. // if ( pRecipientEntity )
  406. // {
  407. // return ShouldBeSentToClient( pRecipientEntity->entindex(), iReturn );
  408. // }
  409. return iReturn;
  410. }
  411. //-----------------------------------------------------------------------------
  412. // Purpose:
  413. //-----------------------------------------------------------------------------
  414. void CEconEntity::UpdateModelToClass( void )
  415. {
  416. #ifdef TF_DLL
  417. MDLCACHE_CRITICAL_SECTION();
  418. CTFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  419. m_iOldOwnerClass = CalculateVisibleClassFor( pPlayer );
  420. if ( !pPlayer )
  421. return;
  422. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  423. if ( !pItem->IsValid() )
  424. return;
  425. const char *pszModel = NULL;
  426. // If we attach to hands, we need to use the hand models
  427. if ( pItem->GetStaticData()->ShouldAttachToHands() )
  428. {
  429. pszModel = pPlayer->GetPlayerClass()->GetHandModelName( 0 );
  430. }
  431. else
  432. {
  433. pszModel = pItem->GetPlayerDisplayModel( m_iOldOwnerClass );
  434. }
  435. if ( pszModel && pszModel[0] )
  436. {
  437. if ( V_stricmp( STRING( GetModelName() ), pszModel ) != 0 )
  438. {
  439. if ( pItem->GetStaticData()->IsContentStreamable() )
  440. {
  441. modelinfo->RegisterDynamicModel( pszModel, IsClient() );
  442. }
  443. SetModel( pszModel );
  444. }
  445. }
  446. if ( GetModelPtr() && pItem->GetStaticData()->UsesPerClassBodygroups( GetTeamNumber() ) )
  447. {
  448. // Classes start at 1, bodygroups at 0, so we shift them all back 1.
  449. SetBodygroup( 1, (m_iOldOwnerClass-1) );
  450. }
  451. #endif
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Purpose:
  455. //-----------------------------------------------------------------------------
  456. void CEconEntity::PlayAnimForPlaybackEvent( wearableanimplayback_t iPlayback )
  457. {
  458. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  459. if ( !pItem->IsValid() || !GetOwnerEntity() )
  460. return;
  461. // Don't do this if we have no model.
  462. if ( !GetModel() || !GetModelPtr() )
  463. return;
  464. int iAnims = pItem->GetStaticData()->GetNumAnimations();
  465. for ( int i = 0; i < iAnims; i++ )
  466. {
  467. animation_on_wearable_t *pData = pItem->GetStaticData()->GetAnimationData( i );
  468. if ( pData && pData->iPlayback == iPlayback && pData->pszActivity )
  469. {
  470. // If this is the first time we've tried to use it, find the activity
  471. if ( pData->iActivity == -2 )
  472. {
  473. pData->iActivity = ActivityList_IndexForName( pData->pszActivity );
  474. }
  475. int sequence = SelectWeightedSequence( (Activity)pData->iActivity );
  476. if ( sequence != ACTIVITY_NOT_AVAILABLE )
  477. {
  478. ResetSequence( sequence );
  479. SetCycle( 0 );
  480. if ( IsUsingClientSideAnimation() )
  481. {
  482. ResetClientsideFrame();
  483. }
  484. }
  485. return;
  486. }
  487. }
  488. }
  489. #endif // #if !defined( CLIENT_DLL )
  490. #if defined( CLIENT_DLL )
  491. // It's okay to draw attached entities with these models.
  492. const char* g_modelWhiteList[] =
  493. {
  494. "models/weapons/w_models/w_toolbox.mdl",
  495. "models/weapons/w_models/w_sapper.mdl",
  496. // These are temporarily white-listed pending a proper fix to using model_player_per_class on weapons. 3/10/2011, BrandonR
  497. "models/weapons/c_models/c_shogun_katana/c_shogun_katana_soldier.mdl",
  498. "models/weapons/c_models/c_shogun_katana/c_shogun_katana.mdl"
  499. };
  500. //-----------------------------------------------------------------------------
  501. // Purpose: TF prevents drawing of any entity attached to players that aren't items in the inventory of the player.
  502. // This is to prevent servers creating fake cosmetic items and attaching them to players.
  503. //-----------------------------------------------------------------------------
  504. bool CEconEntity::ValidateEntityAttachedToPlayer( bool &bShouldRetry )
  505. {
  506. bShouldRetry = false;
  507. // We only use this variable in debug or on the client.
  508. #if defined( _DEBUG ) || defined( TF_CLIENT_DLL )
  509. bool bItemDebugValidation = false;
  510. #endif // defined( _DEBUG ) || defined( TF_CLIENT_DLL )
  511. #ifdef _DEBUG
  512. bItemDebugValidation = item_debug_validation.GetBool();
  513. // Always valid in debug if item_debug_validation is disabled
  514. if ( !bItemDebugValidation )
  515. return true;
  516. #endif // _DEBUG
  517. #if defined( TF_CLIENT_DLL )
  518. // Always valid in item testing mode
  519. if ( TFGameRules()->IsInItemTestingMode() )
  520. return true;
  521. C_TFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );
  522. // If we're not carried by a player, we're not valid. This prevents them
  523. // parenting hats to ents that they then parent to the player.
  524. if ( !pOwner )
  525. {
  526. //Msg( "NO OWNER SET! %i\n", m_iNumOwnerValidationRetries );
  527. bShouldRetry = ( m_iNumOwnerValidationRetries < 500 );
  528. m_iNumOwnerValidationRetries++;
  529. return false;
  530. }
  531. // The owner entity must also be a move parent of this entity.
  532. bool bPlayerIsParented = false;
  533. C_BaseEntity *pEntity = this;
  534. while ( (pEntity = pEntity->GetMoveParent()) != NULL )
  535. {
  536. if ( pOwner == pEntity )
  537. {
  538. bPlayerIsParented = true;
  539. break;
  540. }
  541. }
  542. if ( !bPlayerIsParented )
  543. {
  544. //Msg( "NOT PARENTED! %i\n", m_iNumOwnerValidationRetries );
  545. bShouldRetry = ( m_iNumOwnerValidationRetries < 500 );
  546. m_iNumOwnerValidationRetries++;
  547. return false;
  548. }
  549. m_iNumOwnerValidationRetries = 0;
  550. bool bOwnerIsBot = false;
  551. #if defined( _DEBUG ) || defined( TF_PVE_MODE )
  552. // We only need this in debug (for item_debug_validation) or PvE mode
  553. bOwnerIsBot = pOwner->IsABot(); // THIS IS INSECURE -- DO NOT USE THIS OUTSIDE OF DEBUG OR PVE MODE
  554. #endif
  555. #ifdef TF_PVE_MODE
  556. // Allow bots to use anything in PvE mode
  557. if ( bOwnerIsBot && TFGameRules()->IsPVEModeActive() )
  558. return true;
  559. #endif // TF_PVE_MODE
  560. int iClass = pOwner->GetPlayerClass()->GetClassIndex();
  561. // Allow all weapons parented to the local player
  562. if ( pOwner == C_BasePlayer::GetLocalPlayer() )
  563. {
  564. // They can change the owner entity, so we have to keep checking.
  565. bShouldRetry = true;
  566. return true;
  567. }
  568. // HACK: For now, if our owner is a disguised spy, we assume everything is valid.
  569. if ( (pOwner->m_Shared.InCond( TF_COND_DISGUISED ) || pOwner->m_Shared.InCond( TF_COND_DISGUISING )) && iClass == TF_CLASS_SPY )
  570. {
  571. bShouldRetry = true; // Keep checking in case the player switches class or becomes no longer disguised
  572. return true;
  573. }
  574. // If our owner is a disguised spy, we validate everything based
  575. // on the items carried by the person we're disguised as.
  576. /*if ( pOwner->m_Shared.InCond( TF_COND_DISGUISED ) )
  577. {
  578. // DAMN: This won't work. If our disguise target is a player we've never seen before,
  579. // we won't have a client entity, and hence we don't have their inventory.
  580. C_TFPlayer *pDisguiseTarget = ToTFPlayer( pOwner->m_Shared.GetDisguiseTarget() );
  581. if ( pDisguiseTarget && pDisguiseTarget != pOwner )
  582. {
  583. pOwner = pDisguiseTarget;
  584. iClass = pOwner->GetPlayerClass()->GetClassIndex();
  585. }
  586. else
  587. {
  588. // We're not disguised as a specific player. Make sure we lookup base weapons with the disguise class.
  589. iClass = pOwner->m_Shared.GetDisguiseClass();
  590. }
  591. }
  592. */
  593. const char *pszClientModel = modelinfo->GetModelName( GetModel() );
  594. if ( pszClientModel && g_modelWhiteList[0] )
  595. {
  596. // Certain builder models are okay to have.
  597. for ( int i=0; i<ARRAYSIZE( g_modelWhiteList ); ++i )
  598. {
  599. if ( FStrEq( pszClientModel, g_modelWhiteList[i] ) )
  600. return true;
  601. }
  602. }
  603. // If our player doesn't have an inventory, we're not valid.
  604. CTFPlayerInventory *pInv = pOwner->Inventory();
  605. if ( !pInv )
  606. return false;
  607. // If we've lost connection to the GC, let's just trust the server to avoid breaking the appearance for everyone.
  608. bool bSkipInventoryCheck = bItemDebugValidation && bOwnerIsBot; // will always be false in release builds
  609. if ( ( !pInv->GetSOC() || !pInv->GetSOC()->BIsInitialized() ) && !bSkipInventoryCheck )
  610. {
  611. bShouldRetry = true;
  612. return true;
  613. }
  614. CEconItemView *pScriptItem = GetAttributeContainer()->GetItem();
  615. // If the item isn't valid, we're probably an extra wearable for another item. See if our model is
  616. // a model specified as the extra wearable for any of the items we have equipped.
  617. if ( !pScriptItem->IsValid() )
  618. {
  619. // Uninitialized client models return their model as '?'
  620. if ( pszClientModel && pszClientModel[0] != '?' )
  621. {
  622. CSteamID steamIDForPlayer;
  623. pOwner->GetSteamID( &steamIDForPlayer );
  624. for ( int i = 0; i < LOADOUT_POSITION_COUNT; i++ )
  625. {
  626. CEconItemView *pItem = TFInventoryManager()->GetItemInLoadoutForClass( iClass, i, &steamIDForPlayer );
  627. if ( pItem && pItem->IsValid() )
  628. {
  629. const char *pszAttached = pItem->GetExtraWearableModel();
  630. if ( pszAttached && pszAttached[0] )
  631. {
  632. if ( FStrEq( pszClientModel, pszAttached ) )
  633. return true;
  634. }
  635. }
  636. }
  637. }
  638. else if ( pszClientModel && pszClientModel[0] == '?' )
  639. {
  640. bShouldRetry = true;
  641. }
  642. return false;
  643. }
  644. // Skip this check for bots if item_debug_validation is enabled.
  645. if ( !pInv->GetInventoryItemByItemID( pScriptItem->GetItemID() ) && !bSkipInventoryCheck )
  646. {
  647. // If it's a base item, we allow it.
  648. CEconItemView *pBaseItem = TFInventoryManager()->GetBaseItemForClass( iClass, pScriptItem->GetStaticData()->GetLoadoutSlot(iClass) );
  649. if ( *pScriptItem != *pBaseItem )
  650. {
  651. const wchar_t *pwzItemName = pScriptItem->GetItemName();
  652. char szItemName[ MAX_ITEM_NAME_LENGTH ];
  653. ILocalize::ConvertUnicodeToANSI( pwzItemName, szItemName, sizeof( szItemName ) );
  654. #ifdef _DEBUG
  655. Warning("Item '%s' attached to %s, but it's not in his inventory.\n", szItemName, pOwner->GetPlayerName() );
  656. #endif
  657. return false;
  658. }
  659. }
  660. // Our model has to match the model in our script
  661. const char *pszScriptModel = pScriptItem->GetWorldDisplayModel();
  662. if ( !pszScriptModel )
  663. {
  664. pszScriptModel = pScriptItem->GetPlayerDisplayModel( iClass );
  665. }
  666. if ( pszClientModel && pszClientModel[0] && pszClientModel[0] != '?' )
  667. {
  668. // A model was set on the entity, let's make sure it matches the model in the script.
  669. if ( !pszScriptModel || !pszScriptModel[0] )
  670. return false;
  671. if ( FStrEq( pszClientModel, pszScriptModel ) == false )
  672. return false;
  673. }
  674. else
  675. {
  676. // The client model was not set, so check that there isn't a model set in the script either.
  677. if ( pszScriptModel && pszScriptModel[0] )
  678. {
  679. if ( pszClientModel[0] == '?' )
  680. bShouldRetry = true;
  681. return false;
  682. }
  683. }
  684. return true;
  685. #else
  686. return false;
  687. #endif
  688. }
  689. //-----------------------------------------------------------------------------
  690. // Purpose: Set a material override for this entity via code
  691. //-----------------------------------------------------------------------------
  692. void CEconEntity::SetMaterialOverride( const char *pszMaterial )
  693. {
  694. m_MaterialOverrides.Init( pszMaterial, TEXTURE_GROUP_CLIENT_EFFECTS );
  695. }
  696. //-----------------------------------------------------------------------------
  697. void CEconEntity::SetMaterialOverride( CMaterialReference &ref )
  698. {
  699. m_MaterialOverrides.Init( ref );
  700. }
  701. #ifndef DOTA_DLL
  702. bool C_ViewmodelAttachmentModel::InitializeAsClientEntity( const char *pszModelName, bool bRenderWithViewModels )
  703. {
  704. if ( !BaseClass::InitializeAsClientEntity( pszModelName, bRenderWithViewModels ) )
  705. return false;
  706. AddEffects( EF_BONEMERGE );
  707. AddEffects( EF_BONEMERGE_FASTCULL );
  708. // Invisible by default, and made visible->drawn->made invisible when the viewmodel is drawn
  709. AddEffects( EF_NODRAW );
  710. return true;
  711. }
  712. int C_ViewmodelAttachmentModel::InternalDrawModel( int flags, const RenderableInstance_t &instance )
  713. {
  714. #if defined(TF_CLIENT_DLL)
  715. CMatRenderContextPtr pRenderContext( materials );
  716. if ( cl_flipviewmodels.GetBool() != m_bAlwaysFlip )
  717. {
  718. pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
  719. }
  720. #endif
  721. #if defined( CSTRIKE15 )
  722. CMatRenderContextPtr pRenderContext( materials );
  723. C_BaseViewModel *pViewmodel = m_hViewmodel;
  724. if ( pViewmodel && pViewmodel->ShouldFlipModel() )
  725. pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
  726. #endif
  727. int r = BaseClass::InternalDrawModel( flags, instance );
  728. #if defined(TF_CLIENT_DLL) || defined( CSTRIKE15 )
  729. pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
  730. #endif
  731. return r;
  732. }
  733. void C_ViewmodelAttachmentModel::SetViewmodel( C_BaseViewModel *pVM )
  734. {
  735. m_hViewmodel = pVM;
  736. }
  737. #endif // !defined( DOTA_DLL )
  738. //-----------------------------------------------------------------------------
  739. // Purpose:
  740. //-----------------------------------------------------------------------------
  741. void CEconEntity::SetDormant( bool bDormant )
  742. {
  743. // If I'm burning, stop the burning sounds
  744. if ( !IsDormant() && bDormant && m_bParticleSystemsCreated )
  745. {
  746. SetParticleSystemsVisible( false );
  747. }
  748. BaseClass::SetDormant( bDormant );
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Purpose:
  752. //-----------------------------------------------------------------------------
  753. void CEconEntity::OnPreDataChanged( DataUpdateType_t type )
  754. {
  755. BaseClass::OnPreDataChanged( type );
  756. m_iOldTeam = m_iTeamNum;
  757. }
  758. IMaterial *CreateTempMaterialForPlayerLogo( int iPlayerIndex, player_info_t *info, char *texname, int nchars );
  759. //-----------------------------------------------------------------------------
  760. // Purpose:
  761. //-----------------------------------------------------------------------------
  762. void CEconEntity::OnDataChanged( DataUpdateType_t updateType )
  763. {
  764. // If we were just created, setup from the script files
  765. if ( updateType == DATA_UPDATE_CREATED )
  766. {
  767. InitializeAttributes();
  768. m_bParticleSystemsCreated = false;
  769. m_bAttachmentDirty = true;
  770. }
  771. BaseClass::OnDataChanged( updateType );
  772. GetAttributeContainer()->OnDataChanged( updateType );
  773. if ( updateType == DATA_UPDATE_CREATED )
  774. {
  775. CEconItemView *pItem = m_AttributeManager.GetItem();
  776. #if defined(_DEBUG)
  777. if ( item_debug.GetBool() )
  778. {
  779. DebugDescribe();
  780. }
  781. #endif
  782. // Find & cache for easy leaf code usage
  783. const char *pszMaterial = pItem->GetStaticData()->GetMaterialOverride();
  784. if ( pszMaterial )
  785. {
  786. m_MaterialOverrides.Init( pszMaterial, TEXTURE_GROUP_CLIENT_EFFECTS );
  787. }
  788. #ifdef TF_CLIENT_DLL
  789. // If we're carried by a player, let him know he should recalc his bodygroups.
  790. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  791. if ( pPlayer )
  792. {
  793. pPlayer->SetBodygroupsDirty();
  794. }
  795. //Warning("Forcing recalc of visiblity for %d\n", entindex().GetRaw());
  796. m_bValidatedOwner = false;
  797. m_iNumOwnerValidationRetries = 0;
  798. UpdateVisibility();
  799. #endif // TF_CLIENT_DLL
  800. }
  801. UpdateAttachmentModels();
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Purpose:
  805. //-----------------------------------------------------------------------------
  806. void CEconEntity::UpdateAttachmentModels( void )
  807. {
  808. #ifndef DOTA_DLL
  809. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  810. const GameItemDefinition_t *pItemDef = pItem && pItem->IsValid() ? pItem->GetStaticData() : NULL;
  811. // Update the state of additional model attachments
  812. m_vecAttachedModels.Purge();
  813. if ( pItemDef )
  814. {
  815. int iAttachedModels = pItemDef->GetNumAttachedModels();
  816. for ( int i = 0; i < iAttachedModels; i++ )
  817. {
  818. attachedmodel_t *pModel = pItemDef->GetAttachedModelData( i );
  819. int iModelIndex = modelinfo->GetModelIndex( pModel->m_pszModelName );
  820. if ( iModelIndex >= 0 )
  821. {
  822. AttachedModelData_t attachedModelData;
  823. attachedModelData.m_pModel = modelinfo->GetModel( iModelIndex );
  824. attachedModelData.m_iModelDisplayFlags = pModel->m_iModelDisplayFlags;
  825. m_vecAttachedModels.AddToTail( attachedModelData );
  826. }
  827. }
  828. }
  829. // Update the state of attachment models for this item
  830. bool bItemNeedsAttachment = pItemDef && (pItemDef->ShouldAttachToHands() || pItemDef->ShouldAttachToHandsVMOnly());
  831. if ( bItemNeedsAttachment )
  832. {
  833. bool bShouldShowAttachment = false;
  834. CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  835. CBasePlayer *pOwner = ToBasePlayer( GetOwnerEntity() );
  836. bShouldShowAttachment = ( pOwner && (pOwner == pLocalPlayer) || ( pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE && pLocalPlayer->GetObserverTarget() == pOwner ) );
  837. if ( bShouldShowAttachment && AttachmentModelsShouldBeVisible() )
  838. {
  839. if ( !m_hViewmodelAttachment )
  840. {
  841. C_BaseViewModel *vm = pOwner->GetViewModel( 0 );
  842. if ( vm )
  843. {
  844. C_ViewmodelAttachmentModel *pEnt = new class C_ViewmodelAttachmentModel;
  845. if ( !pEnt )
  846. return;
  847. if ( pEnt->InitializeAsClientEntity( pItem->GetPlayerDisplayModel(), true ) == false )
  848. return;
  849. m_hViewmodelAttachment = pEnt;
  850. m_hViewmodelAttachment->SetParent( vm );
  851. m_hViewmodelAttachment->SetLocalOrigin( vec3_origin );
  852. m_hViewmodelAttachment->UpdatePartitionListEntry();
  853. m_hViewmodelAttachment->CollisionProp()->UpdatePartition();
  854. m_hViewmodelAttachment->UpdateVisibility();
  855. m_bAttachmentDirty = true;
  856. }
  857. }
  858. else if ( m_hViewmodelAttachment )
  859. {
  860. // If a player changes team, we may need to update the skin on the attachment weapon model
  861. if ( m_iOldTeam != m_iTeamNum )
  862. {
  863. m_bAttachmentDirty = true;
  864. }
  865. }
  866. return;
  867. }
  868. }
  869. // If we get here we shouldn't have an attachment.
  870. if ( m_hViewmodelAttachment )
  871. {
  872. m_hViewmodelAttachment->Release();
  873. }
  874. #endif // !defined( DOTA_DLL )
  875. }
  876. //-----------------------------------------------------------------z------------
  877. // Purpose: Create / Destroy particle systems on this item as appropriate
  878. //-----------------------------------------------------------------------------
  879. void CEconEntity::UpdateParticleSystems( void )
  880. {
  881. if ( !HasCustomParticleSystems() )
  882. return;
  883. bool bVisible = false;
  884. if ( IsEffectActive( EF_NODRAW ))
  885. {
  886. bVisible = false;
  887. }
  888. else if ( !GetOwnerEntity() && !IsDormant() )
  889. {
  890. bVisible = true;
  891. }
  892. else if ( GetOwnerEntity() && !GetOwnerEntity()->IsDormant() )
  893. {
  894. // Dota heroes turn off particle effects when they're dead
  895. if ( GetOwnerEntity()->IsAlive() )
  896. {
  897. bVisible = true;
  898. }
  899. }
  900. if ( bVisible )
  901. {
  902. bVisible = ShouldDrawParticleSystems();
  903. }
  904. SetParticleSystemsVisible( bVisible );
  905. }
  906. //-----------------------------------------------------------------------------
  907. // Purpose:
  908. //-----------------------------------------------------------------------------
  909. bool CEconEntity::ShouldDrawParticleSystems( void )
  910. {
  911. if ( !ShouldDraw() )
  912. return false;
  913. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  914. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  915. if ( pPlayer )
  916. {
  917. bool bStealthed = pPlayer->m_Shared.InCond( TF_COND_STEALTHED );
  918. if ( bStealthed )
  919. return false;
  920. bool bDisguised = pPlayer->m_Shared.InCond( TF_COND_DISGUISED );
  921. if ( bDisguised )
  922. {
  923. CTFWeaponBase *pWeapon = dynamic_cast<CTFWeaponBase*>( this );
  924. bool bDisguiseWeapon = pWeapon && pWeapon->m_bDisguiseWeapon;
  925. if ( !bDisguiseWeapon )
  926. {
  927. return false;
  928. }
  929. }
  930. }
  931. #endif
  932. // Make sure the entity we're attaching to is being drawn
  933. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  934. if ( pLocalPlayer )
  935. {
  936. C_BaseEntity *pEffectOwner = this;
  937. if ( pLocalPlayer == GetOwnerEntity() && pLocalPlayer->GetViewModel() && !pLocalPlayer->ShouldDrawLocalPlayer() )
  938. {
  939. pEffectOwner = pLocalPlayer->GetViewModel();
  940. }
  941. if ( !pEffectOwner->ShouldDraw() )
  942. {
  943. return false;
  944. }
  945. }
  946. return true;
  947. }
  948. //-----------------------------------------------------------------------------
  949. // Purpose:
  950. //-----------------------------------------------------------------------------
  951. void CEconEntity::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  952. {
  953. if ( !InternalFireEvent( origin, angles, event, options ) )
  954. {
  955. BaseClass::FireEvent( origin, angles, event, options );
  956. }
  957. }
  958. //-----------------------------------------------------------------------------
  959. // Purpose:
  960. //-----------------------------------------------------------------------------
  961. bool CEconEntity::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
  962. {
  963. return InternalFireEvent( origin, angles, event, options );
  964. }
  965. //-----------------------------------------------------------------------------
  966. // Purpose:
  967. //-----------------------------------------------------------------------------
  968. bool CEconEntity::InternalFireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  969. {
  970. switch( event )
  971. {
  972. case AE_CL_BODYGROUP_SET_VALUE_CMODEL_WPN:
  973. if ( m_hViewmodelAttachment )
  974. {
  975. // Translate it into a set bodygroup event on our attached weapon
  976. m_hViewmodelAttachment->FireEvent( origin, angles, AE_CL_BODYGROUP_SET_VALUE, options );
  977. }
  978. return true;
  979. break;
  980. }
  981. return false;
  982. }
  983. //-----------------------------------------------------------------------------
  984. // Purpose: Does this model use delayed flex weights?
  985. //-----------------------------------------------------------------------------
  986. bool CEconEntity::UsesFlexDelayedWeights()
  987. {
  988. return m_flFlexDelayedWeight != NULL;
  989. }
  990. //-----------------------------------------------------------------------------
  991. // Purpose: Rendering callback to allow the client to set up all the model specific flex weights
  992. //-----------------------------------------------------------------------------
  993. void CEconEntity::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
  994. {
  995. /*
  996. if ( GetModelPtr() && GetModelPtr()->numflexcontrollers() )
  997. {
  998. if ( IsEffectActive( EF_BONEMERGE ) && GetMoveParent() )
  999. {
  1000. C_BaseFlex *pParentFlex = dynamic_cast<C_BaseFlex*>( GetMoveParent() );
  1001. if ( pParentFlex )
  1002. {
  1003. if ( pParentFlex->SetupGlobalWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights ) )
  1004. {
  1005. // convert the flex controllers into actual flex values
  1006. C_BaseFlex::RunFlexRules( GetModelPtr(), pFlexWeights );
  1007. // aim the eyes
  1008. // SetViewTarget( hdr ); // FIXME: Not enough info yet
  1009. // process local versions of the delay weights
  1010. if ( pFlexDelayedWeights )
  1011. {
  1012. C_BaseFlex::RunFlexDelay( nFlexWeightCount, pFlexWeights, m_flFlexDelayedWeight, m_flFlexDelayTime );
  1013. memcpy( pFlexDelayedWeights, m_flFlexDelayedWeight, sizeof( float ) * nFlexWeightCount );
  1014. }
  1015. return;
  1016. }
  1017. }
  1018. }
  1019. }
  1020. */
  1021. BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
  1022. return;
  1023. }
  1024. //-----------------------------------------------------------------------------
  1025. // Purpose:
  1026. //-----------------------------------------------------------------------------
  1027. static void cc_dump_particlemanifest()
  1028. {
  1029. Msg("Dumping particle list:\n");
  1030. for ( int i = 0; i < g_pParticleSystemMgr->GetParticleSystemCount(); i++ )
  1031. {
  1032. const char *pParticleSystemName = g_pParticleSystemMgr->GetParticleSystemNameFromIndex(i);
  1033. Msg(" %d: %s\n", i, pParticleSystemName );
  1034. }
  1035. }
  1036. static ConCommand dump_particlemanifest( "dump_particlemanifest", cc_dump_particlemanifest, "Dump the list of particles loaded.", FCVAR_CHEAT );
  1037. //-----------------------------------------------------------------------------
  1038. // Purpose:
  1039. //-----------------------------------------------------------------------------
  1040. void CEconEntity::SetParticleSystemsVisible( bool bVisible )
  1041. {
  1042. if ( bVisible == m_bParticleSystemsCreated )
  1043. return;
  1044. if ( !HasCustomParticleSystems() )
  1045. return;
  1046. int iSystems = m_AttributeManager.GetItem()->GetStaticData()->GetNumAttachedParticles();
  1047. for ( int i = 0; i < iSystems; i++ )
  1048. {
  1049. attachedparticlesystem_t *pSystem = m_AttributeManager.GetItem()->GetStaticData()->GetAttachedParticleData( i );
  1050. Assert( pSystem->pszSystemName && pSystem->pszSystemName[0] );
  1051. // Ignore custom particles. Weapons handle them in custom fashions.
  1052. if ( pSystem->iCustomType )
  1053. continue;
  1054. UpdateSingleParticleSystem( bVisible, pSystem );
  1055. }
  1056. // Now check for particle systems that controlled on by specific attributes
  1057. int iCustomParticleEffect = GetCustomParticleEffectId( this );
  1058. if ( iCustomParticleEffect > 0 )
  1059. {
  1060. attachedparticlesystem_t *pSystem = GetItemSchema()->GetAttributeControlledParticleSystem( iCustomParticleEffect );
  1061. if ( pSystem )
  1062. {
  1063. iCustomParticleEffect--;
  1064. if ( pSystem->iCount > 0 )
  1065. {
  1066. // Support X particles attached to X attachment points
  1067. for ( int i = 0; i < pSystem->iCount; i++ )
  1068. {
  1069. UpdateSingleParticleSystem( bVisible, pSystem, UTIL_VarArgs("%s%d", pSystem->pszAttachmentName, i+1 ) );
  1070. }
  1071. }
  1072. else
  1073. {
  1074. UpdateSingleParticleSystem( bVisible, pSystem );
  1075. }
  1076. }
  1077. }
  1078. m_bParticleSystemsCreated = bVisible;
  1079. }
  1080. //-----------------------------------------------------------------------------
  1081. // Purpose:
  1082. //-----------------------------------------------------------------------------
  1083. void CEconEntity::UpdateSingleParticleSystem( bool bVisible, attachedparticlesystem_t *pSystem, const char *pszAttachmentName )
  1084. {
  1085. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1086. if ( !pLocalPlayer )
  1087. return;
  1088. if ( !pszAttachmentName )
  1089. {
  1090. pszAttachmentName = pSystem->pszAttachmentName;
  1091. }
  1092. C_BaseEntity *pEffectOwner = this;
  1093. if ( pSystem->nAttachToEntity == ATTPART_TO_PARENT )
  1094. {
  1095. pEffectOwner = GetOwnerEntity();
  1096. }
  1097. if ( bVisible && pEffectOwner )
  1098. {
  1099. // We can't have fastcull on if we want particles attached to us
  1100. if ( pEffectOwner == this )
  1101. {
  1102. RemoveEffects( EF_BONEMERGE_FASTCULL );
  1103. }
  1104. #ifdef DOTA_DLL
  1105. C_DOTA_BaseNPC *pNPC = ToDOTABaseNPC( pEffectOwner );
  1106. if ( pNPC )
  1107. pNPC->CopyParticlesToPortrait( true );
  1108. bool bAttachTypeSet = (pSystem->nRootAttachType != 1);
  1109. int iIndex = -1;
  1110. bool bAttached = false;
  1111. if ( pszAttachmentName && pszAttachmentName[0] && pEffectOwner->GetBaseAnimating() )
  1112. {
  1113. int iAttachment = pEffectOwner->GetBaseAnimating()->LookupAttachment( pszAttachmentName );
  1114. if ( iAttachment != INVALID_PARTICLE_ATTACHMENT )
  1115. {
  1116. iIndex = GetParticleManager()->CreateParticle( GetParticleManager()->GetParticleReplacement( pSystem->pszSystemName, GetOwnerEntity() ), bAttachTypeSet ? pSystem->nRootAttachType : PATTACH_POINT_FOLLOW, pEffectOwner );
  1117. m_vecAttachedParticles.AddToTail( iIndex );
  1118. bAttached = true;
  1119. }
  1120. }
  1121. // Attachments can fall back to following root bones if the attachment point wasn't found
  1122. if ( !bAttached )
  1123. {
  1124. if ( bAttachTypeSet )
  1125. {
  1126. iIndex = GetParticleManager()->CreateParticle( GetParticleManager()->GetParticleReplacement( pSystem->pszSystemName, GetOwnerEntity() ), pSystem->nRootAttachType, pEffectOwner );
  1127. m_vecAttachedParticles.AddToTail( iIndex );
  1128. }
  1129. else
  1130. {
  1131. if ( pSystem->bFollowRootBone )
  1132. {
  1133. iIndex = GetParticleManager()->CreateParticle( GetParticleManager()->GetParticleReplacement( pSystem->pszSystemName, GetOwnerEntity() ), PATTACH_ROOTBONE_FOLLOW, pEffectOwner );
  1134. }
  1135. else
  1136. {
  1137. iIndex = GetParticleManager()->CreateParticle( GetParticleManager()->GetParticleReplacement( pSystem->pszSystemName, GetOwnerEntity() ), PATTACH_ABSORIGIN_FOLLOW, pEffectOwner );
  1138. }
  1139. m_vecAttachedParticles.AddToTail( iIndex );
  1140. }
  1141. }
  1142. // Now init any control points
  1143. if ( iIndex != -1 )
  1144. {
  1145. FOR_EACH_VEC( pSystem->vecControlPoints, i )
  1146. {
  1147. attachedparticlecontrolpoint_t *pCP = &pSystem->vecControlPoints[i];
  1148. if ( pCP->nAttachType == PATTACH_CUSTOMORIGIN || pCP->nAttachType == PATTACH_WORLDORIGIN )
  1149. GetParticleManager()->SetParticleControl( iIndex, pCP->nControlPoint, pCP->vecPosition );
  1150. else
  1151. GetParticleManager()->SetParticleControlEnt( iIndex, pCP->nControlPoint, pEffectOwner, pCP->nAttachType, pCP->pszAttachmentName );
  1152. }
  1153. // If we're a Strange Type, set CP 13 to our current value
  1154. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  1155. if ( pItem )
  1156. {
  1157. static CSchemaAttributeDefHandle pAttrDef_KillEaterAttribute( "kill eater" );
  1158. uint32 unKillEater;
  1159. if ( pItem->FindAttribute( pAttrDef_KillEaterAttribute, &unKillEater ) )
  1160. {
  1161. GetParticleManager()->SetParticleControl( iIndex, 13, Vector( unKillEater, 1, 1 ) );
  1162. }
  1163. const CDOTAItemDefinition *pDef = pItem->GetStaticData();
  1164. for ( int nCPIndex = 0; nCPIndex < pDef->GetNumParticleControlPoints(); ++nCPIndex )
  1165. {
  1166. int nWhichCP;
  1167. Vector vecCPValue;
  1168. bool bHasCP = pDef->GetReplacementControlPoint( nCPIndex, GetParticleManager()->GetParticleReplacement( pSystem->pszSystemName, GetOwnerEntity() ), nWhichCP, vecCPValue );
  1169. if ( bHasCP )
  1170. {
  1171. GetParticleManager()->SetParticleControl( iIndex, nWhichCP, vecCPValue );
  1172. }
  1173. }
  1174. }
  1175. }
  1176. if ( pNPC )
  1177. pNPC->CopyParticlesToPortrait( false );
  1178. #endif //#ifdef DOTA_DLL
  1179. }
  1180. else
  1181. {
  1182. #ifdef DOTA_DLL
  1183. FOR_EACH_VEC( m_vecAttachedParticles, i )
  1184. {
  1185. GetParticleManager()->DestroyParticleEffect( m_vecAttachedParticles[i], true );
  1186. }
  1187. m_vecAttachedParticles.RemoveAll();
  1188. #endif //#ifdef DOTA_DLL
  1189. }
  1190. }
  1191. //-----------------------------------------------------------------------------
  1192. // Purpose:
  1193. //-----------------------------------------------------------------------------
  1194. bool CEconEntity::InitializeAsClientEntity( const char *pszModelName, bool bRenderWithViewModels )
  1195. {
  1196. m_bClientside = true;
  1197. return BaseClass::InitializeAsClientEntity( pszModelName, bRenderWithViewModels );
  1198. }
  1199. //-----------------------------------------------------------------------------
  1200. // Purpose:
  1201. //-----------------------------------------------------------------------------
  1202. int CEconEntity::InternalDrawModel( int flags, const RenderableInstance_t &instance )
  1203. {
  1204. bool bUseOverride = m_MaterialOverrides.IsValid();
  1205. if ( bUseOverride && (flags & STUDIO_RENDER) )
  1206. {
  1207. modelrender->ForcedMaterialOverride( m_MaterialOverrides );
  1208. }
  1209. int ret = BaseClass::InternalDrawModel( flags, instance );
  1210. if ( bUseOverride && (flags & STUDIO_RENDER) )
  1211. {
  1212. modelrender->ForcedMaterialOverride( NULL );
  1213. }
  1214. return ret;
  1215. }
  1216. //-----------------------------------------------------------------------------
  1217. // Purpose:
  1218. //-----------------------------------------------------------------------------
  1219. bool CEconEntity::ViewModel_IsTransparent( void )
  1220. {
  1221. if ( m_hViewmodelAttachment != NULL && m_hViewmodelAttachment->IsTransparent() )
  1222. {
  1223. return true;
  1224. }
  1225. return IsTransparent();
  1226. }
  1227. //-----------------------------------------------------------------------------
  1228. // Purpose:
  1229. //-----------------------------------------------------------------------------
  1230. bool CEconEntity::ViewModel_IsUsingFBTexture( void )
  1231. {
  1232. // if ( m_hViewmodelAttachment != NULL && m_hViewmodelAttachment->UsesPowerOfTwoFrameBufferTexture() )
  1233. // {
  1234. // return true;
  1235. // }
  1236. // return UsesPowerOfTwoFrameBufferTexture();
  1237. return false;
  1238. }
  1239. //-----------------------------------------------------------------------------
  1240. // Purpose:
  1241. //-----------------------------------------------------------------------------
  1242. bool CEconEntity::IsOverridingViewmodel( void )
  1243. {
  1244. bool bUseOverride = m_MaterialOverrides.IsValid();
  1245. bUseOverride = bUseOverride || (m_hViewmodelAttachment != NULL) || ( m_AttributeManager.GetItem()->GetStaticData()->GetNumAttachedModels() > 0 );
  1246. return bUseOverride;
  1247. }
  1248. //-----------------------------------------------------------------------------
  1249. // Purpose:
  1250. //-----------------------------------------------------------------------------
  1251. int CEconEntity::DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags )
  1252. {
  1253. int ret = 0;
  1254. #ifdef TF_DLL
  1255. bool bIsAttachmentTranslucent = m_hViewmodelAttachment.Get() ? m_hViewmodelAttachment->IsTransparent() : false;
  1256. bool bUseOverride = false;
  1257. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  1258. bool bAttachesToHands = ( pItem->IsValid() && (pItem->GetStaticData()->ShouldAttachToHands() || pItem->GetStaticData()->ShouldAttachToHandsVMOnly()));
  1259. // If the attachment is translucent, we need to render the viewmodel first
  1260. if ( bIsAttachmentTranslucent )
  1261. {
  1262. ret = pViewmodel->DrawOverriddenViewmodel( flags );
  1263. }
  1264. if ( flags & STUDIO_RENDER )
  1265. {
  1266. bUseOverride = m_MaterialOverrides.IsValid();
  1267. if ( bUseOverride )
  1268. {
  1269. modelrender->ForcedMaterialOverride( m_MaterialOverrides );
  1270. }
  1271. if ( m_hViewmodelAttachment )
  1272. {
  1273. m_hViewmodelAttachment->RemoveEffects( EF_NODRAW );
  1274. m_hViewmodelAttachment->DrawModel( flags );
  1275. m_hViewmodelAttachment->AddEffects( EF_NODRAW );
  1276. }
  1277. // if we are attached to the hands, then we DO NOT want have an override material when we draw our view model
  1278. if ( bAttachesToHands && bUseOverride )
  1279. {
  1280. modelrender->ForcedMaterialOverride( NULL );
  1281. bUseOverride = false;
  1282. }
  1283. }
  1284. if ( !bIsAttachmentTranslucent )
  1285. {
  1286. ret = pViewmodel->DrawOverriddenViewmodel( flags );
  1287. }
  1288. if ( bUseOverride )
  1289. {
  1290. modelrender->ForcedMaterialOverride( NULL );
  1291. }
  1292. #endif // #ifdef TF_DLL
  1293. return ret;
  1294. }
  1295. //-----------------------------------------------------------------------------
  1296. // Purpose:
  1297. //-----------------------------------------------------------------------------
  1298. bool CEconEntity::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo )
  1299. {
  1300. if ( !BaseClass::OnInternalDrawModel( pInfo ) )
  1301. return false;
  1302. DrawEconEntityAttachedModels( this, this, pInfo, kAttachedModelDisplayFlag_WorldModel );
  1303. return true;
  1304. }
  1305. //-----------------------------------------------------------------------------
  1306. // Purpose:
  1307. //-----------------------------------------------------------------------------
  1308. int CEconEntity::LookupAttachment( const char *pAttachmentName )
  1309. {
  1310. if ( m_hViewmodelAttachment )
  1311. return m_hViewmodelAttachment->LookupAttachment( pAttachmentName );
  1312. return BaseClass::LookupAttachment( pAttachmentName );
  1313. }
  1314. //-----------------------------------------------------------------------------
  1315. // Purpose:
  1316. //-----------------------------------------------------------------------------
  1317. bool CEconEntity::GetAttachment( int number, matrix3x4_t &matrix )
  1318. {
  1319. if ( m_hViewmodelAttachment )
  1320. return m_hViewmodelAttachment->GetAttachment( number, matrix );
  1321. return BaseClass::GetAttachment( number, matrix );
  1322. }
  1323. //-----------------------------------------------------------------------------
  1324. // Purpose:
  1325. //-----------------------------------------------------------------------------
  1326. bool CEconEntity::GetAttachment( int number, Vector &origin )
  1327. {
  1328. if ( m_hViewmodelAttachment )
  1329. return m_hViewmodelAttachment->GetAttachment( number, origin );
  1330. return BaseClass::GetAttachment( number, origin );
  1331. }
  1332. //-----------------------------------------------------------------------------
  1333. // Purpose:
  1334. //-----------------------------------------------------------------------------
  1335. bool CEconEntity::GetAttachment( int number, Vector &origin, QAngle &angles )
  1336. {
  1337. if ( m_hViewmodelAttachment )
  1338. return m_hViewmodelAttachment->GetAttachment( number, origin, angles );
  1339. return BaseClass::GetAttachment( number, origin, angles );
  1340. }
  1341. //-----------------------------------------------------------------------------
  1342. // Purpose:
  1343. //-----------------------------------------------------------------------------
  1344. bool CEconEntity::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
  1345. {
  1346. if ( m_hViewmodelAttachment )
  1347. return m_hViewmodelAttachment->GetAttachmentVelocity( number, originVel, angleVel );
  1348. return BaseClass::GetAttachmentVelocity( number, originVel, angleVel );
  1349. }
  1350. #endif // #if defined( CLIENT_DLL )
  1351. //-----------------------------------------------------------------------------
  1352. // Purpose:
  1353. //-----------------------------------------------------------------------------
  1354. bool CEconEntity::HasCustomParticleSystems( void )
  1355. {
  1356. if ( m_AttributeManager.GetItem()->GetStaticData()->GetNumAttachedParticles() )
  1357. return true;
  1358. int iCustomParticleEffect = GetCustomParticleEffectId( this );
  1359. return ( iCustomParticleEffect > 0 && GetItemSchema()->GetAttributeControlledParticleSystem( iCustomParticleEffect ) != NULL );
  1360. }
  1361. //-----------------------------------------------------------------------------
  1362. // Purpose: Hides or shows masked bodygroups associated with this item.
  1363. //-----------------------------------------------------------------------------
  1364. bool CEconEntity::UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState )
  1365. {
  1366. if ( !pOwner )
  1367. return false;
  1368. CAttributeContainer *pCont = GetAttributeContainer();
  1369. if ( !pCont )
  1370. return false;
  1371. CEconItemView *pItem = pCont->GetItem();
  1372. if ( !pItem )
  1373. return false;
  1374. const CEconItemDefinition *pItemDef = pItem->GetItemDefinition();
  1375. if ( !pItemDef )
  1376. return false;
  1377. int iNumBodyGroups = pItemDef->GetNumModifiedBodyGroups();
  1378. for ( int i=0; i<iNumBodyGroups; ++i )
  1379. {
  1380. int iBody = 0;
  1381. const char *pszBodyGroup = pItemDef->GetModifiedBodyGroup( i, iBody );
  1382. int iBodyGroup = pOwner->FindBodygroupByName( pszBodyGroup );
  1383. if ( iBodyGroup == -1 )
  1384. continue;
  1385. pOwner->SetBodygroup( iBodyGroup, pItemDef->IsBaseItem() ? 0 : iState );
  1386. }
  1387. // Handle per-style bodygroup hiding
  1388. const CEconStyleInfo *pStyle = pItemDef->GetStyleInfo( pItem->GetStyle() );
  1389. if ( pStyle )
  1390. {
  1391. FOR_EACH_VEC( pStyle->GetAdditionalHideBodygroups(), i )
  1392. {
  1393. int iBodyGroup = pOwner->FindBodygroupByName( pStyle->GetAdditionalHideBodygroups()[i] );
  1394. if ( iBodyGroup == -1 )
  1395. continue;
  1396. pOwner->SetBodygroup( iBodyGroup, iState );
  1397. }
  1398. }
  1399. // Handle world model bodygroup overrides
  1400. int iBodyOverride = pItemDef->GetWorldmodelBodygroupOverride();
  1401. int iBodyStateOverride = pItemDef->GetWorldmodelBodygroupStateOverride();
  1402. if ( iBodyOverride > -1 && iBodyStateOverride > -1 )
  1403. {
  1404. pOwner->SetBodygroup( iBodyOverride, iBodyStateOverride );
  1405. }
  1406. // Handle view model bodygroup overrides
  1407. iBodyOverride = pItemDef->GetViewmodelBodygroupOverride();
  1408. iBodyStateOverride = pItemDef->GetViewmodelBodygroupStateOverride();
  1409. if ( iBodyOverride > -1 && iBodyStateOverride > -1 )
  1410. {
  1411. CBasePlayer *pPlayer = ToBasePlayer( pOwner );
  1412. if ( pPlayer )
  1413. {
  1414. CBaseViewModel *pVM = pPlayer->GetViewModel();
  1415. if ( pVM )
  1416. {
  1417. pVM->SetBodygroup( iBodyOverride, iBodyStateOverride );
  1418. }
  1419. }
  1420. }
  1421. return true;
  1422. }
  1423. //-----------------------------------------------------------------------------
  1424. // Purpose:
  1425. //-----------------------------------------------------------------------------
  1426. CBaseAttributableItem::CBaseAttributableItem()
  1427. {
  1428. }
  1429. loadout_positions_t CEconEntity::GetLoadoutPosition( int iTeam /*= 0 */ ) const
  1430. {
  1431. return ( loadout_positions_t ) GetAttributeContainer()->GetItem()->GetStaticData()->GetLoadoutSlot( iTeam );
  1432. }
  1433. const CEconItemView* CEconEntity::GetEconItemView( void ) const
  1434. {
  1435. return m_AttributeManager.GetItem();
  1436. }