Team Fortress 2 Source Code as on 22/4/2020
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.

2078 lines
64 KiB

  1. //========= Copyright 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. #include "cdll_util.h"
  17. #if defined(TF_CLIENT_DLL)
  18. #include "c_tf_player.h"
  19. #include "tf_gamerules.h"
  20. #include "c_playerresource.h"
  21. #include "tf_shareddefs.h"
  22. #endif
  23. #else // defined( CLIENT_DLL )
  24. #include "activitylist.h"
  25. #if defined(TF_DLL)
  26. #include "tf_player.h"
  27. #endif
  28. #endif // defined( CLIENT_DLL )
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include "tier0/memdbgon.h"
  31. IMPLEMENT_NETWORKCLASS_ALIASED( EconEntity, DT_EconEntity )
  32. IMPLEMENT_NETWORKCLASS_ALIASED( BaseAttributableItem, DT_BaseAttributableItem )
  33. #if defined( CLIENT_DLL )
  34. bool ParseItemKeyvalue( void *pObject, typedescription_t *pFields, int iNumFields, const char *szKeyName, const char *szValue );
  35. #endif
  36. #if defined(_DEBUG)
  37. extern ConVar item_debug;
  38. extern ConVar item_debug_validation;
  39. #endif
  40. #if !defined( CLIENT_DLL )
  41. #define DEFINE_ECON_ENTITY_NETWORK_TABLE() \
  42. SendPropDataTable( SENDINFO_DT( m_AttributeManager ), &REFERENCE_SEND_TABLE(DT_AttributeContainer) ),
  43. #else
  44. #define DEFINE_ECON_ENTITY_NETWORK_TABLE() \
  45. RecvPropDataTable( RECVINFO_DT( m_AttributeManager ), 0, &REFERENCE_RECV_TABLE(DT_AttributeContainer) ),
  46. #endif // CLIENT_DLL
  47. BEGIN_NETWORK_TABLE( CEconEntity , DT_EconEntity )
  48. DEFINE_ECON_ENTITY_NETWORK_TABLE()
  49. #if defined(TF_DLL)
  50. SendPropBool( SENDINFO( m_bValidatedAttachedEntity ) ),
  51. #elif defined(TF_CLIENT_DLL)
  52. RecvPropBool( RECVINFO( m_bValidatedAttachedEntity ) ),
  53. #endif // TF_DLL || TF_CLIENT_DLL
  54. END_NETWORK_TABLE()
  55. BEGIN_DATADESC( CEconEntity )
  56. END_DATADESC()
  57. //
  58. // Duplicating CEconEntity's network table and data description for backwards compat with demos.
  59. // NOTE: NOTE_RENAMED_RECVTABLE() will not work with this class.
  60. //
  61. BEGIN_NETWORK_TABLE( CBaseAttributableItem, DT_BaseAttributableItem )
  62. DEFINE_ECON_ENTITY_NETWORK_TABLE()
  63. END_NETWORK_TABLE()
  64. BEGIN_DATADESC( CBaseAttributableItem )
  65. END_DATADESC()
  66. #ifdef TF_CLIENT_DLL
  67. extern ConVar cl_flipviewmodels;
  68. #ifdef STAGING_ONLY
  69. ConVar unusual_force_weapon_effect( "unusual_force_weapon_effect", "-1", FCVAR_CHEAT, "Set to force an Unusual effect on your weapon (Primary, Secondary, Melee)" );
  70. ConVar unusual_force_cosmetic_effect( "unusual_force_cosmetic_effect", "-1", FCVAR_CHEAT, "Set to force an Unusual effect on your equipped cosmetics" );
  71. #endif
  72. #endif
  73. #ifdef CLIENT_DLL
  74. //-----------------------------------------------------------------------------
  75. // Purpose:
  76. //-----------------------------------------------------------------------------
  77. void DrawEconEntityAttachedModels( CBaseAnimating *pEnt, CEconEntity *pAttachedModelSource, const ClientModelRenderInfo_t *pInfo, int iMatchDisplayFlags )
  78. {
  79. #ifndef DOTA_DLL
  80. if ( !pEnt || !pAttachedModelSource || !pInfo )
  81. return;
  82. // This flag says we should turn off the material overrides for attachments.
  83. IMaterial* pMaterialOverride = NULL;
  84. OverrideType_t nMaterialOverrideType = OVERRIDE_NORMAL;
  85. if ( ( pInfo->flags & STUDIO_NO_OVERRIDE_FOR_ATTACH ) != 0 )
  86. {
  87. modelrender->GetMaterialOverride( &pMaterialOverride, &nMaterialOverrideType );
  88. modelrender->ForcedMaterialOverride( NULL, nMaterialOverrideType );
  89. }
  90. // Draw our attached models as well
  91. for ( int i = 0; i < pAttachedModelSource->m_vecAttachedModels.Size(); i++ )
  92. {
  93. const AttachedModelData_t& attachedModel = pAttachedModelSource->m_vecAttachedModels[i];
  94. if ( attachedModel.m_pModel && (attachedModel.m_iModelDisplayFlags & iMatchDisplayFlags) )
  95. {
  96. ClientModelRenderInfo_t infoAttached = *pInfo;
  97. infoAttached.pRenderable = pEnt;
  98. infoAttached.instance = MODEL_INSTANCE_INVALID;
  99. infoAttached.entity_index = pEnt->index;
  100. infoAttached.pModel = attachedModel.m_pModel;
  101. infoAttached.pModelToWorld = &infoAttached.modelToWorld;
  102. // Turns the origin + angles into a matrix
  103. AngleMatrix( infoAttached.angles, infoAttached.origin, infoAttached.modelToWorld );
  104. DrawModelState_t state;
  105. matrix3x4_t *pBoneToWorld;
  106. bool bMarkAsDrawn = modelrender->DrawModelSetup( infoAttached, &state, NULL, &pBoneToWorld );
  107. pEnt->DoInternalDrawModel( &infoAttached, ( bMarkAsDrawn && ( infoAttached.flags & STUDIO_RENDER ) ) ? &state : NULL, pBoneToWorld );
  108. }
  109. }
  110. if ( pMaterialOverride != NULL )
  111. modelrender->ForcedMaterialOverride( pMaterialOverride, nMaterialOverrideType );
  112. #endif
  113. }
  114. #endif // CLIENT_DLL
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. //-----------------------------------------------------------------------------
  118. CEconEntity::CEconEntity()
  119. {
  120. m_pAttributes = this;
  121. // Inform base entity system that we can deal with dynamic models
  122. EnableDynamicModels();
  123. #ifdef GAME_DLL
  124. m_iOldOwnerClass = 0;
  125. #endif
  126. #if defined(TF_DLL) || defined(TF_CLIENT_DLL)
  127. m_bValidatedAttachedEntity = false;
  128. #endif // TF_DLL || TF_CLIENT_DLL
  129. #ifdef CLIENT_DLL
  130. m_flFlexDelayTime = 0.0f;
  131. m_flFlexDelayedWeight = NULL;
  132. m_cFlexDelayedWeight = 0;
  133. m_iNumOwnerValidationRetries = 0;
  134. #endif
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose:
  138. //-----------------------------------------------------------------------------
  139. CEconEntity::~CEconEntity()
  140. {
  141. #ifdef CLIENT_DLL
  142. SetParticleSystemsVisible( PARTICLE_SYSTEM_STATE_NOT_VISIBLE );
  143. delete [] m_flFlexDelayedWeight;
  144. #endif
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Purpose:
  148. //-----------------------------------------------------------------------------
  149. CStudioHdr * CEconEntity::OnNewModel()
  150. {
  151. CStudioHdr* hdr = BaseClass::OnNewModel();
  152. #ifdef GAME_DLL
  153. // Adjust class-specific bodygroup after model load if we have a model and a class
  154. if ( hdr && m_iOldOwnerClass > 0 )
  155. {
  156. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  157. if ( pItem && pItem->IsValid() && pItem->GetStaticData()->UsesPerClassBodygroups( GetTeamNumber() ) )
  158. {
  159. // Classes start at 1, bodygroups at 0
  160. SetBodygroup( 1, m_iOldOwnerClass - 1 );
  161. }
  162. }
  163. #endif
  164. #ifdef TF_CLIENT_DLL
  165. m_bValidatedOwner = false; // require item validation to re-run
  166. // If we're carried by a player, let him know he should recalc his bodygroups.
  167. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  168. if ( pPlayer )
  169. {
  170. pPlayer->SetBodygroupsDirty();
  171. }
  172. // allocate room for delayed flex weights
  173. delete [] m_flFlexDelayedWeight;
  174. m_flFlexDelayedWeight = NULL;
  175. m_cFlexDelayedWeight = 0;
  176. if ( hdr && hdr->numflexcontrollers() )
  177. {
  178. m_cFlexDelayedWeight = hdr->numflexcontrollers();
  179. m_flFlexDelayedWeight = new float[ m_cFlexDelayedWeight ];
  180. memset( m_flFlexDelayedWeight, 0, sizeof( float ) * m_cFlexDelayedWeight );
  181. C_BaseFlex::LinkToGlobalFlexControllers( hdr );
  182. }
  183. #endif // TF_CLIENT_DLL
  184. return hdr;
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Purpose:
  188. //-----------------------------------------------------------------------------
  189. void CEconEntity::InitializeAttributes( void )
  190. {
  191. m_AttributeManager.InitializeAttributes( this );
  192. m_AttributeManager.SetProviderType( PROVIDER_WEAPON );
  193. #ifdef CLIENT_DLL
  194. // Check particle systems
  195. CUtlVector<const attachedparticlesystem_t *> vecParticles;
  196. GetEconParticleSystems( &vecParticles );
  197. m_bHasParticleSystems = vecParticles.Count() > 0;
  198. if ( !m_bClientside )
  199. return;
  200. #else
  201. m_AttributeManager.GetItem()->InitNetworkedDynamicAttributesForDemos();
  202. #endif
  203. }
  204. //-----------------------------------------------------------------------------
  205. // Purpose:
  206. //-----------------------------------------------------------------------------
  207. void CEconEntity::DebugDescribe( void )
  208. {
  209. CEconItemView *pScriptItem = GetAttributeContainer()->GetItem();
  210. Msg("============================================\n");
  211. char tempstr[1024];
  212. // FIXME: ILocalize::ConvertUnicodeToANSI( pScriptItem->GetItemName(), tempstr, sizeof(tempstr) );
  213. const char *pszQualityString = EconQuality_GetQualityString( (EEconItemQuality)pScriptItem->GetItemQuality() );
  214. Msg("%s \"%s\" (level %d)\n", pszQualityString ? pszQualityString : "[unknown]", tempstr, pScriptItem->GetItemLevel() );
  215. // FIXME: ILocalize::ConvertUnicodeToANSI( pScriptItem->GetAttributeDescription(), tempstr, sizeof(tempstr) );
  216. Msg("%s", tempstr );
  217. Msg("\n============================================\n");
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose:
  221. //-----------------------------------------------------------------------------
  222. void CEconEntity::UpdateOnRemove( void )
  223. {
  224. SetOwnerEntity( NULL );
  225. ReapplyProvision();
  226. BaseClass::UpdateOnRemove();
  227. }
  228. //-----------------------------------------------------------------------------
  229. // Purpose:
  230. //-----------------------------------------------------------------------------
  231. void CEconEntity::ReapplyProvision( void )
  232. {
  233. #ifdef GAME_DLL
  234. UpdateModelToClass();
  235. #endif
  236. CBaseEntity *pNewOwner = GetOwnerEntity();
  237. if ( pNewOwner == m_hOldProvidee.Get() )
  238. return;
  239. // Remove ourselves from the old providee's list
  240. if ( m_hOldProvidee.Get() )
  241. {
  242. GetAttributeManager()->StopProvidingTo( m_hOldProvidee.Get() );
  243. }
  244. // Add ourselves to our new owner's provider list
  245. if ( pNewOwner )
  246. {
  247. GetAttributeManager()->ProvideTo( pNewOwner );
  248. }
  249. m_hOldProvidee = pNewOwner;
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Purpose:
  253. //-----------------------------------------------------------------------------
  254. Activity CEconEntity::TranslateViewmodelHandActivity( Activity actBase )
  255. {
  256. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  257. if ( pItem && pItem->IsValid() )
  258. {
  259. GameItemDefinition_t *pStaticData = pItem->GetStaticData();
  260. if ( pStaticData && pStaticData->ShouldAttachToHands() )
  261. {
  262. return TranslateViewmodelHandActivityInternal(actBase);
  263. }
  264. }
  265. return actBase;
  266. }
  267. #if !defined( CLIENT_DLL )
  268. //-----------------------------------------------------------------------------
  269. // Purpose:
  270. //-----------------------------------------------------------------------------
  271. void CEconEntity::OnOwnerClassChange( void )
  272. {
  273. #ifdef TF_DLL
  274. CTFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  275. if ( pPlayer && pPlayer->GetPlayerClass()->GetClassIndex() != m_iOldOwnerClass )
  276. {
  277. UpdateModelToClass();
  278. }
  279. #endif
  280. }
  281. #ifdef GAME_DLL
  282. //-----------------------------------------------------------------------------
  283. // Purpose:
  284. //-----------------------------------------------------------------------------
  285. int CEconEntity::CalculateVisibleClassFor( CBaseCombatCharacter *pPlayer )
  286. {
  287. #ifdef TF_DLL
  288. CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
  289. return (pTFPlayer ? pTFPlayer->GetPlayerClass()->GetClassIndex() : 0);
  290. #else
  291. return 0;
  292. #endif
  293. }
  294. #endif
  295. //-----------------------------------------------------------------------------
  296. // Purpose: double duty function - sets up model for current player class, and
  297. // also sets bodygroups if the correct model is fully loaded.
  298. //-----------------------------------------------------------------------------
  299. void CEconEntity::UpdateModelToClass( void )
  300. {
  301. #ifdef TF_DLL
  302. MDLCACHE_CRITICAL_SECTION();
  303. CTFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  304. m_iOldOwnerClass = CalculateVisibleClassFor( pPlayer );
  305. if ( !pPlayer )
  306. return;
  307. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  308. if ( !pItem->IsValid() )
  309. return;
  310. const char *pszModel = NULL;
  311. // If we attach to hands, we need to use the hand models
  312. if ( pItem->GetStaticData()->ShouldAttachToHands() )
  313. {
  314. pszModel = pPlayer->GetPlayerClass()->GetHandModelName( 0 );
  315. }
  316. else
  317. {
  318. int nTeam = pPlayer->GetTeamNumber();
  319. CTFWearable *pWearable = dynamic_cast< CTFWearable*>( this );
  320. if ( pWearable && pWearable->IsDisguiseWearable() )
  321. {
  322. nTeam = pPlayer->m_Shared.GetDisguiseTeam();
  323. }
  324. pszModel = pItem->GetPlayerDisplayModel( m_iOldOwnerClass, nTeam );
  325. }
  326. if ( pszModel && pszModel[0] )
  327. {
  328. if ( V_stricmp( STRING( GetModelName() ), pszModel ) != 0 )
  329. {
  330. if ( pItem->GetStaticData()->IsContentStreamable() )
  331. {
  332. modelinfo->RegisterDynamicModel( pszModel, IsClient() );
  333. const char *pszModelAlt = pItem->GetStaticData()->GetPlayerDisplayModelAlt( m_iOldOwnerClass );
  334. if ( pszModelAlt && pszModelAlt[0] )
  335. {
  336. modelinfo->RegisterDynamicModel( pszModelAlt, IsClient() );
  337. }
  338. if ( pItem->GetVisionFilteredDisplayModel() && pItem->GetVisionFilteredDisplayModel()[ 0 ] != '\0' )
  339. {
  340. modelinfo->RegisterDynamicModel( pItem->GetVisionFilteredDisplayModel(), IsClient() );
  341. }
  342. }
  343. SetModel( pszModel );
  344. }
  345. }
  346. if ( GetModelPtr() && pItem->GetStaticData()->UsesPerClassBodygroups( GetTeamNumber() ) )
  347. {
  348. // Classes start at 1, bodygroups at 0, so we shift them all back 1.
  349. SetBodygroup( 1, (m_iOldOwnerClass-1) );
  350. }
  351. #endif
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose:
  355. //-----------------------------------------------------------------------------
  356. void CEconEntity::PlayAnimForPlaybackEvent( wearableanimplayback_t iPlayback )
  357. {
  358. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  359. if ( !pItem->IsValid() || !GetOwnerEntity() )
  360. return;
  361. int iTeamNum = GetOwnerEntity()->GetTeamNumber();
  362. int iActivities = pItem->GetStaticData()->GetNumPlaybackActivities( iTeamNum );
  363. for ( int i = 0; i < iActivities; i++ )
  364. {
  365. activity_on_wearable_t *pData = pItem->GetStaticData()->GetPlaybackActivityData( iTeamNum, i );
  366. if ( pData && pData->iPlayback == iPlayback && pData->pszActivity )
  367. {
  368. // If this is the first time we've tried to use it, find the activity
  369. if ( pData->iActivity == kActivityLookup_Unknown )
  370. {
  371. pData->iActivity = ActivityList_IndexForName( pData->pszActivity );
  372. }
  373. int sequence = SelectWeightedSequence( (Activity)pData->iActivity );
  374. if ( sequence != ACTIVITY_NOT_AVAILABLE )
  375. {
  376. ResetSequence( sequence );
  377. SetCycle( 0 );
  378. #if !defined( CLIENT_DLL )
  379. if ( IsUsingClientSideAnimation() )
  380. {
  381. ResetClientsideFrame();
  382. }
  383. #endif
  384. }
  385. return;
  386. }
  387. }
  388. }
  389. #endif // !CLIENT_DLL
  390. #if defined( TF_CLIENT_DLL )
  391. // It's okay to draw attached entities with these models.
  392. const char* g_modelWhiteList[] =
  393. {
  394. "models/weapons/w_models/w_toolbox.mdl",
  395. "models/weapons/w_models/w_sapper.mdl",
  396. // Canteens can change model based on the powerup type... all of these alternates are ok!
  397. "models/player/items/mvm_loot/all_class/mvm_flask_krit.mdl",
  398. "models/player/items/mvm_loot/all_class/mvm_flask_uber.mdl",
  399. "models/player/items/mvm_loot/all_class/mvm_flask_tele.mdl",
  400. "models/player/items/mvm_loot/all_class/mvm_flask_ammo.mdl",
  401. "models/player/items/mvm_loot/all_class/mvm_flask_build.mdl",
  402. TF_WEAPON_TAUNT_FRONTIER_JUSTICE_GUITAR_MODEL,
  403. "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_pack.mdl",
  404. "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_pack_open.mdl",
  405. };
  406. #define HALLOWEEN_KART_MODEL "models/player/items/taunts/bumpercar/parts/bumpercar.mdl"
  407. #define HALLOWEEN_KART_CAGE_MODEL "models/props_halloween/bumpercar_cage.mdl"
  408. #endif
  409. #if defined( CLIENT_DLL )
  410. //-----------------------------------------------------------------------------
  411. // Purpose: TF prevents drawing of any entity attached to players that aren't items in the inventory of the player.
  412. // This is to prevent servers creating fake cosmetic items and attaching them to players.
  413. //-----------------------------------------------------------------------------
  414. bool CEconEntity::ValidateEntityAttachedToPlayer( bool &bShouldRetry )
  415. {
  416. bShouldRetry = false;
  417. // We only use this variable in debug or on the client.
  418. #if defined( _DEBUG ) || defined( TF_CLIENT_DLL )
  419. bool bItemDebugValidation = false;
  420. #endif // defined( _DEBUG ) || defined( TF_CLIENT_DLL )
  421. #ifdef _DEBUG
  422. bItemDebugValidation = item_debug_validation.GetBool();
  423. // Always valid in debug if item_debug_validation is disabled
  424. if ( !bItemDebugValidation )
  425. return true;
  426. #endif // _DEBUG
  427. #if defined( TF_CLIENT_DLL )
  428. // Always valid in item testing mode
  429. if ( TFGameRules()->IsInItemTestingMode() )
  430. return true;
  431. C_TFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );
  432. // If we're not carried by a player, we're not valid. This prevents them
  433. // parenting hats to ents that they then parent to the player.
  434. if ( !pOwner )
  435. {
  436. //Msg( "NO OWNER SET! %i\n", m_iNumOwnerValidationRetries );
  437. bShouldRetry = ( m_iNumOwnerValidationRetries < 500 );
  438. m_iNumOwnerValidationRetries++;
  439. return false;
  440. }
  441. C_BaseEntity *pVM = pOwner->GetViewModel();
  442. // The owner entity must also be a move parent of this entity.
  443. bool bPlayerIsParented = false;
  444. C_BaseEntity *pEntity = this;
  445. while ( (pEntity = pEntity->GetMoveParent()) != NULL )
  446. {
  447. if ( pOwner == pEntity || pVM == pEntity )
  448. {
  449. bPlayerIsParented = true;
  450. break;
  451. }
  452. }
  453. if ( !bPlayerIsParented )
  454. {
  455. //Msg( "NOT PARENTED! %i\n", m_iNumOwnerValidationRetries );
  456. bShouldRetry = ( m_iNumOwnerValidationRetries < 500 );
  457. m_iNumOwnerValidationRetries++;
  458. return false;
  459. }
  460. m_iNumOwnerValidationRetries = 0;
  461. // We only need this in debug (for item_debug_validation) or PvE mode
  462. bool bOwnerIsBot = pOwner->IsABot(); // THIS IS INSECURE -- DO NOT USE THIS OUTSIDE OF DEBUG OR PVE MODE
  463. // Allow bots to use anything in PvE mode
  464. if ( bOwnerIsBot && TFGameRules()->IsPVEModeActive() )
  465. return true;
  466. int iClass = pOwner->GetPlayerClass()->GetClassIndex();
  467. int iTeam = pOwner->GetTeamNumber();
  468. // Allow all weapons parented to the local player
  469. if ( pOwner == C_BasePlayer::GetLocalPlayer() )
  470. {
  471. // They can change the owner entity, so we have to keep checking.
  472. bShouldRetry = true;
  473. return true;
  474. }
  475. // HACK: For now, if our owner is a disguised spy, we assume everything is valid.
  476. if ( (pOwner->m_Shared.InCond( TF_COND_DISGUISED ) || pOwner->m_Shared.InCond( TF_COND_DISGUISING )) && iClass == TF_CLASS_SPY )
  477. {
  478. bShouldRetry = true; // Keep checking in case the player switches class or becomes no longer disguised
  479. return true;
  480. }
  481. // If our owner is a disguised spy, we validate everything based
  482. // on the items carried by the person we're disguised as.
  483. /*if ( pOwner->m_Shared.InCond( TF_COND_DISGUISED ) )
  484. {
  485. // DAMN: This won't work. If our disguise target is a player we've never seen before,
  486. // we won't have a client entity, and hence we don't have their inventory.
  487. C_TFPlayer *pDisguiseTarget = ToTFPlayer( pOwner->m_Shared.GetDisguiseTarget() );
  488. if ( pDisguiseTarget && pDisguiseTarget != pOwner )
  489. {
  490. pOwner = pDisguiseTarget;
  491. iClass = pOwner->GetPlayerClass()->GetClassIndex();
  492. }
  493. else
  494. {
  495. // We're not disguised as a specific player. Make sure we lookup base weapons with the disguise class.
  496. iClass = pOwner->m_Shared.GetDisguiseClass();
  497. }
  498. }
  499. */
  500. #if defined(TF_DLL) || defined(TF_CLIENT_DLL)
  501. if ( m_bValidatedAttachedEntity )
  502. return true;
  503. #endif // TF_DLL || TF_CLIENT_DLL
  504. const char *pszClientModel = modelinfo->GetModelName( GetModel() );
  505. if ( pszClientModel && g_modelWhiteList[0] )
  506. {
  507. // Certain builder models are okay to have.
  508. for ( int i=0; i<ARRAYSIZE( g_modelWhiteList ); ++i )
  509. {
  510. if ( FStrEq( pszClientModel, g_modelWhiteList[i] ) )
  511. return true;
  512. }
  513. }
  514. // Halloween Karts
  515. if ( pOwner->m_Shared.InCond( TF_COND_HALLOWEEN_KART ) )
  516. {
  517. if ( FStrEq( pszClientModel, HALLOWEEN_KART_MODEL ) )
  518. return true;
  519. if ( FStrEq( pszClientModel, HALLOWEEN_KART_CAGE_MODEL ) )
  520. return true;
  521. }
  522. // If our player doesn't have an inventory, we're not valid.
  523. CTFPlayerInventory *pInv = pOwner->Inventory();
  524. if ( !pInv )
  525. return false;
  526. // check if this is a custom taunt prop
  527. if ( pOwner->m_Shared.InCond( TF_COND_TAUNTING ) )
  528. {
  529. const char* pszCustomTauntProp = NULL;
  530. int iClassTaunt = pOwner->GetPlayerClass()->GetClassIndex();
  531. CEconItemView *pMiscItemView = pInv->GetItemInLoadout( iClassTaunt, pOwner->GetActiveTauntSlot() );
  532. if ( pMiscItemView && pMiscItemView->IsValid() )
  533. {
  534. if ( pMiscItemView->GetStaticData()->GetTauntData() )
  535. {
  536. pszCustomTauntProp = pMiscItemView->GetStaticData()->GetTauntData()->GetProp( iClassTaunt );
  537. if ( pszCustomTauntProp )
  538. {
  539. return true;
  540. }
  541. }
  542. }
  543. }
  544. // If we've lost connection to the GC, let's just trust the server to avoid breaking the appearance for everyone.
  545. bool bSkipInventoryCheck = bItemDebugValidation && bOwnerIsBot; // will always be false in release builds
  546. if ( ( !pInv->GetSOC() || !pInv->GetSOC()->BIsInitialized() ) && !bSkipInventoryCheck )
  547. {
  548. bShouldRetry = true;
  549. return true;
  550. }
  551. CEconItemView *pScriptItem = GetAttributeContainer()->GetItem();
  552. // If the item isn't valid, we're probably an extra wearable for another item. See if our model is
  553. // a model specified as the extra wearable for any of the items we have equipped.
  554. if ( !pScriptItem->IsValid() )
  555. {
  556. // Uninitialized client models return their model as '?'
  557. if ( pszClientModel && pszClientModel[0] != '?' )
  558. {
  559. CSteamID steamIDForPlayer;
  560. pOwner->GetSteamID( &steamIDForPlayer );
  561. for ( int i = 0; i < CLASS_LOADOUT_POSITION_COUNT; i++ )
  562. {
  563. CEconItemView *pItem = TFInventoryManager()->GetItemInLoadoutForClass( iClass, i, &steamIDForPlayer );
  564. if ( pItem && pItem->IsValid() )
  565. {
  566. const char *pszAttached = pItem->GetExtraWearableModel();
  567. if ( pszAttached && pszAttached[0] )
  568. {
  569. if ( FStrEq( pszClientModel, pszAttached ) )
  570. return true;
  571. }
  572. pszAttached = pItem->GetExtraWearableViewModel();
  573. if ( pszAttached && pszAttached[0] )
  574. {
  575. if ( FStrEq( pszClientModel, pszAttached ) )
  576. return true;
  577. }
  578. }
  579. }
  580. }
  581. else if ( pszClientModel && pszClientModel[0] == '?' )
  582. {
  583. bShouldRetry = true;
  584. }
  585. return false;
  586. }
  587. // Skip this check for bots if item_debug_validation is enabled.
  588. if ( !pInv->GetInventoryItemByItemID( pScriptItem->GetItemID() ) && !bSkipInventoryCheck )
  589. {
  590. // If it's a base item, we allow it.
  591. CEconItemView *pBaseItem = TFInventoryManager()->GetBaseItemForClass( iClass, pScriptItem->GetStaticData()->GetLoadoutSlot(iClass) );
  592. if ( *pScriptItem != *pBaseItem )
  593. {
  594. const wchar_t *pwzItemName = pScriptItem->GetItemName();
  595. char szItemName[ MAX_ITEM_NAME_LENGTH ];
  596. ILocalize::ConvertUnicodeToANSI( pwzItemName, szItemName, sizeof( szItemName ) );
  597. #ifdef _DEBUG
  598. Warning("Item '%s' attached to %s, but it's not in his inventory.\n", szItemName, pOwner->GetPlayerName() );
  599. #endif
  600. return false;
  601. }
  602. }
  603. // Our model has to match the model in our script
  604. const char *pszScriptModel = pScriptItem->GetWorldDisplayModel();
  605. if ( !pszScriptModel )
  606. {
  607. pszScriptModel = pScriptItem->GetPlayerDisplayModel( iClass, iTeam );
  608. }
  609. if ( pszClientModel && pszClientModel[0] && pszClientModel[0] != '?' )
  610. {
  611. // A model was set on the entity, let's make sure it matches the model in the script.
  612. if ( !pszScriptModel || !pszScriptModel[0] )
  613. return false;
  614. if ( FStrEq( pszClientModel, pszScriptModel ) == false )
  615. {
  616. #if defined( STAGING_ONLY ) && defined _DEBUG
  617. CUtlString strScriptModel( pszScriptModel );
  618. strScriptModel.FixSlashes();
  619. CUtlString strClientModel( pszClientModel );
  620. strClientModel.FixSlashes();
  621. AssertMsg( strScriptModel != strClientModel, "Model path separator differs between script and client!" );
  622. #endif // STAGING_ONLY
  623. // The regular model didn't work...let's try the Alt version if it exists
  624. const char *pszScriptModelAlt = pScriptItem->GetStaticData()->GetPlayerDisplayModelAlt( iClass );
  625. if ( !pszScriptModelAlt || !pszScriptModelAlt[0] || ( FStrEq( pszClientModel, pszScriptModelAlt ) == false ) )
  626. {
  627. // The Alt model didn't work... let's try the vision filtered display model if it happens to exist
  628. pszScriptModel = pScriptItem->GetVisionFilteredDisplayModel();
  629. if ( !pszScriptModel || !pszScriptModel[0] )
  630. return false;
  631. if ( FStrEq( pszClientModel, pszScriptModel ) == false )
  632. {
  633. return false;
  634. }
  635. }
  636. }
  637. }
  638. else
  639. {
  640. // The client model was not set, so check that there isn't a model set in the script either.
  641. if ( pszScriptModel && pszScriptModel[0] )
  642. {
  643. if ( pszClientModel[0] == '?' )
  644. bShouldRetry = true;
  645. return false;
  646. }
  647. }
  648. return true;
  649. #else
  650. return false;
  651. #endif
  652. }
  653. //-----------------------------------------------------------------------------
  654. // Purpose: Set a material override for this entity via code
  655. //-----------------------------------------------------------------------------
  656. void CEconEntity::SetMaterialOverride( int team, const char *pszMaterial )
  657. {
  658. if ( team >= 0 && team < TEAM_VISUAL_SECTIONS )
  659. {
  660. m_MaterialOverrides[ team ].Init( pszMaterial, TEXTURE_GROUP_CLIENT_EFFECTS );
  661. }
  662. }
  663. //-----------------------------------------------------------------------------
  664. void CEconEntity::SetMaterialOverride( int team, CMaterialReference &ref )
  665. {
  666. if ( team >= 0 && team < TEAM_VISUAL_SECTIONS )
  667. {
  668. m_MaterialOverrides[ team ].Init( ref );
  669. }
  670. }
  671. // Deal with recording
  672. void CEconEntity::GetToolRecordingState( KeyValues *msg )
  673. {
  674. #ifndef _XBOX
  675. BaseClass::GetToolRecordingState( msg );
  676. bool bUseOverride = ( GetTeamNumber() >= 0 && GetTeamNumber() < TEAM_VISUAL_SECTIONS ) && m_MaterialOverrides[ GetTeamNumber() ].IsValid();
  677. if ( bUseOverride )
  678. {
  679. msg->SetString( "materialOverride", m_MaterialOverrides[ GetTeamNumber() ]->GetName() );
  680. }
  681. #endif
  682. }
  683. #ifndef DOTA_DLL
  684. //-----------------------------------------------------------------------------
  685. // Purpose:
  686. //-----------------------------------------------------------------------------
  687. void C_ViewmodelAttachmentModel::SetOuter( CEconEntity *pOuter )
  688. {
  689. m_hOuter = pOuter;
  690. SetOwnerEntity( pOuter );
  691. CEconItemView *pItem = pOuter->GetAttributeContainer()->GetItem();
  692. if ( pItem->IsValid() )
  693. {
  694. m_bAlwaysFlip = pItem->GetStaticData()->ShouldFlipViewmodels();
  695. }
  696. }
  697. bool C_ViewmodelAttachmentModel::InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup )
  698. {
  699. if ( !BaseClass::InitializeAsClientEntity( pszModelName, renderGroup ) )
  700. return false;
  701. AddEffects( EF_BONEMERGE );
  702. AddEffects( EF_BONEMERGE_FASTCULL );
  703. // Invisible by default, and made visible->drawn->made invisible when the viewmodel is drawn
  704. AddEffects( EF_NODRAW );
  705. return true;
  706. }
  707. int C_ViewmodelAttachmentModel::InternalDrawModel( int flags )
  708. {
  709. #ifdef TF_CLIENT_DLL
  710. CMatRenderContextPtr pRenderContext( materials );
  711. if ( cl_flipviewmodels.GetBool() != m_bAlwaysFlip )
  712. {
  713. pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
  714. }
  715. #endif
  716. int r = BaseClass::InternalDrawModel( flags );
  717. #ifdef TF_CLIENT_DLL
  718. pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
  719. #endif
  720. return r;
  721. }
  722. bool C_ViewmodelAttachmentModel::OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo )
  723. {
  724. if ( !BaseClass::OnPostInternalDrawModel( pInfo ) )
  725. return false;
  726. if ( !m_hOuter )
  727. return true;
  728. if ( !m_hOuter->GetAttributeContainer() )
  729. return true;
  730. if ( !m_hOuter->GetAttributeContainer()->GetItem() )
  731. return true;
  732. DrawEconEntityAttachedModels( this, GetOuter(), pInfo, kAttachedModelDisplayFlag_ViewModel );
  733. return true;
  734. }
  735. void C_ViewmodelAttachmentModel::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask )
  736. {
  737. BaseClass::StandardBlendingRules( hdr, pos, q, currentTime, boneMask );
  738. // Will it blend?
  739. if ( !m_hOuter )
  740. return;
  741. m_hOuter->ViewModelAttachmentBlending( hdr, pos, q, currentTime, boneMask );
  742. }
  743. void FormatViewModelAttachment( Vector &vOrigin, bool bInverse );
  744. void C_ViewmodelAttachmentModel::FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld )
  745. {
  746. Vector vecOrigin;
  747. MatrixPosition( attachmentToWorld, vecOrigin );
  748. ::FormatViewModelAttachment( vecOrigin, false );
  749. PositionMatrix( vecOrigin, attachmentToWorld );
  750. }
  751. int C_ViewmodelAttachmentModel::GetSkin( void )
  752. {
  753. if ( m_hOuter != NULL )
  754. {
  755. CBaseCombatWeapon *pWeapon = m_hOuter->MyCombatWeaponPointer();
  756. if ( pWeapon )
  757. {
  758. int nSkin = pWeapon->GetSkinOverride();
  759. if ( nSkin != -1 )
  760. {
  761. return nSkin;
  762. }
  763. }
  764. else
  765. {
  766. // some models like the Festive Targe don't have combat pointers but they still need to get the correct skin
  767. if ( m_hOuter->GetAttributeContainer() )
  768. {
  769. CEconItemView *pItem = m_hOuter->GetAttributeContainer()->GetItem();
  770. if ( pItem && pItem->IsValid() && GetOwnerViaInterface() )
  771. {
  772. return pItem->GetSkin( GetOwnerViaInterface()->GetTeamNumber(), true );
  773. }
  774. }
  775. }
  776. }
  777. return BaseClass::GetSkin();
  778. }
  779. #endif // !defined( DOTA_DLL )
  780. //-----------------------------------------------------------------------------
  781. // Purpose:
  782. //-----------------------------------------------------------------------------
  783. void CEconEntity::Release( void )
  784. {
  785. #ifdef CLIENT_DLL
  786. SetParticleSystemsVisible( PARTICLE_SYSTEM_STATE_NOT_VISIBLE );
  787. // Remove all effects associated with this econ entity, not just turn them off
  788. C_BaseEntity *pEffectOwnerWM = this;
  789. C_BaseEntity *pEffectOwnerVM = NULL;
  790. bool bExtraWearable = false;
  791. bool bExtraWearableVM = false;
  792. CTFWeaponBase *pWeapon = dynamic_cast<CTFWeaponBase*>( this );
  793. if ( pWeapon )
  794. {
  795. pEffectOwnerVM = pWeapon->GetPlayerOwner() ? pWeapon->GetPlayerOwner()->GetViewModel() : NULL;
  796. if ( pWeapon->m_hExtraWearable.Get() )
  797. {
  798. pEffectOwnerWM = pWeapon->m_hExtraWearable.Get();
  799. bExtraWearable = true;
  800. }
  801. if ( pWeapon->m_hExtraWearableViewModel.Get() )
  802. {
  803. pEffectOwnerVM = pWeapon->m_hExtraWearableViewModel.Get();
  804. bExtraWearableVM = true;
  805. }
  806. // always kill all effects for VM
  807. if ( pEffectOwnerVM )
  808. {
  809. pEffectOwnerVM->ParticleProp()->StopEmission( NULL, false, true );
  810. }
  811. }
  812. pEffectOwnerWM->ParticleProp()->StopEmission( NULL, false, true );
  813. #endif
  814. if ( m_hViewmodelAttachment )
  815. {
  816. m_hViewmodelAttachment->Release();
  817. }
  818. BaseClass::Release();
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Purpose:
  822. //-----------------------------------------------------------------------------
  823. void CEconEntity::SetDormant( bool bDormant )
  824. {
  825. // If I'm burning, stop the burning sounds
  826. if ( !IsDormant() && bDormant && m_nParticleSystemsCreated != PARTICLE_SYSTEM_STATE_NOT_VISIBLE )
  827. {
  828. SetParticleSystemsVisible( PARTICLE_SYSTEM_STATE_NOT_VISIBLE );
  829. }
  830. BaseClass::SetDormant( bDormant );
  831. }
  832. //-----------------------------------------------------------------------------
  833. // Purpose:
  834. //-----------------------------------------------------------------------------
  835. void CEconEntity::OnPreDataChanged( DataUpdateType_t type )
  836. {
  837. BaseClass::OnPreDataChanged( type );
  838. m_iOldTeam = m_iTeamNum;
  839. }
  840. IMaterial *CreateTempMaterialForPlayerLogo( int iPlayerIndex, player_info_t *info, char *texname, int nchars );
  841. //-----------------------------------------------------------------------------
  842. // Purpose:
  843. //-----------------------------------------------------------------------------
  844. void CEconEntity::OnDataChanged( DataUpdateType_t updateType )
  845. {
  846. // If we were just created, setup from the script files
  847. if ( updateType == DATA_UPDATE_CREATED )
  848. {
  849. InitializeAttributes();
  850. m_nParticleSystemsCreated = PARTICLE_SYSTEM_STATE_NOT_VISIBLE;
  851. m_bAttachmentDirty = true;
  852. }
  853. BaseClass::OnDataChanged( updateType );
  854. GetAttributeContainer()->OnDataChanged( updateType );
  855. if ( updateType == DATA_UPDATE_CREATED )
  856. {
  857. CEconItemView *pItem = m_AttributeManager.GetItem();
  858. #if defined(_DEBUG)
  859. if ( item_debug.GetBool() )
  860. {
  861. DebugDescribe();
  862. }
  863. #endif
  864. // Find & cache for easy leaf code usage
  865. for ( int team = 0; team < TEAM_VISUAL_SECTIONS; team++ )
  866. {
  867. const char *pszMaterial = pItem->GetStaticData()->GetMaterialOverride( team );
  868. if ( pszMaterial )
  869. {
  870. m_MaterialOverrides[team].Init( pszMaterial, TEXTURE_GROUP_CLIENT_EFFECTS );
  871. }
  872. }
  873. #ifdef TF_CLIENT_DLL
  874. // If we're carried by a player, let him know he should recalc his bodygroups.
  875. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  876. if ( pPlayer )
  877. {
  878. pPlayer->SetBodygroupsDirty();
  879. }
  880. //Warning("Forcing recalc of visiblity for %d\n", entindex());
  881. m_bValidatedOwner = false;
  882. m_iNumOwnerValidationRetries = 0;
  883. UpdateVisibility();
  884. #endif // TF_CLIENT_DLL
  885. }
  886. UpdateAttachmentModels();
  887. }
  888. //-----------------------------------------------------------------------------
  889. // Purpose:
  890. //-----------------------------------------------------------------------------
  891. void CEconEntity::UpdateAttachmentModels( void )
  892. {
  893. #ifndef DOTA_DLL
  894. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  895. GameItemDefinition_t *pItemDef = pItem && pItem->IsValid() ? pItem->GetStaticData() : NULL;
  896. // Update the state of additional model attachments
  897. m_vecAttachedModels.Purge();
  898. if ( pItemDef && AttachmentModelsShouldBeVisible() )
  899. {
  900. int iTeamNumber = GetTeamNumber();
  901. {
  902. int iAttachedModels = pItemDef->GetNumAttachedModels( iTeamNumber );
  903. for ( int i = 0; i < iAttachedModels; i++ )
  904. {
  905. attachedmodel_t *pModel = pItemDef->GetAttachedModelData( iTeamNumber, i );
  906. int iModelIndex = modelinfo->GetModelIndex( pModel->m_pszModelName );
  907. if ( iModelIndex >= 0 )
  908. {
  909. AttachedModelData_t attachedModelData;
  910. attachedModelData.m_pModel = modelinfo->GetModel( iModelIndex );
  911. attachedModelData.m_iModelDisplayFlags = pModel->m_iModelDisplayFlags;
  912. m_vecAttachedModels.AddToTail( attachedModelData );
  913. }
  914. }
  915. }
  916. // Check for Festive attachedmodels for festivized weapons
  917. {
  918. int iAttachedModels = pItemDef->GetNumAttachedModelsFestivized( iTeamNumber );
  919. if ( iAttachedModels )
  920. {
  921. int iFestivized = 0;
  922. CALL_ATTRIB_HOOK_INT( iFestivized, is_festivized );
  923. if ( iFestivized )
  924. {
  925. for ( int i = 0; i < iAttachedModels; i++ )
  926. {
  927. attachedmodel_t *pModel = pItemDef->GetAttachedModelDataFestivized( iTeamNumber, i );
  928. int iModelIndex = modelinfo->GetModelIndex( pModel->m_pszModelName );
  929. if ( iModelIndex >= 0 )
  930. {
  931. AttachedModelData_t attachedModelData;
  932. attachedModelData.m_pModel = modelinfo->GetModel( iModelIndex );
  933. attachedModelData.m_iModelDisplayFlags = pModel->m_iModelDisplayFlags;
  934. m_vecAttachedModels.AddToTail( attachedModelData );
  935. }
  936. }
  937. }
  938. }
  939. }
  940. }
  941. // Update the state of attachment models for this item
  942. bool bItemNeedsAttachment = pItemDef && (pItemDef->ShouldAttachToHands() || pItemDef->ShouldAttachToHandsVMOnly());
  943. if ( bItemNeedsAttachment )
  944. {
  945. bool bShouldShowAttachment = false;
  946. CBasePlayer *pOwner = ToBasePlayer( GetOwnerEntity() );
  947. if ( pOwner && !pOwner->ShouldDrawThisPlayer() )
  948. {
  949. // Drawing the viewmodel
  950. bShouldShowAttachment = true;
  951. }
  952. if ( bShouldShowAttachment && AttachmentModelsShouldBeVisible() )
  953. {
  954. if ( !m_hViewmodelAttachment )
  955. {
  956. C_BaseViewModel *vm = pOwner->GetViewModel( 0 );
  957. if ( vm )
  958. {
  959. C_ViewmodelAttachmentModel *pEnt = new class C_ViewmodelAttachmentModel;
  960. if ( !pEnt )
  961. return;
  962. pEnt->SetOuter( this );
  963. int iClass = 0;
  964. #if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  965. CTFPlayer *pTFPlayer = ToTFPlayer( pOwner );
  966. if ( pTFPlayer )
  967. {
  968. iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
  969. }
  970. #endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  971. if ( pEnt->InitializeAsClientEntity( pItem->GetPlayerDisplayModel( iClass, pOwner->GetTeamNumber() ), RENDER_GROUP_VIEW_MODEL_OPAQUE ) == false )
  972. return;
  973. m_hViewmodelAttachment = pEnt;
  974. m_hViewmodelAttachment->SetParent( vm );
  975. m_hViewmodelAttachment->SetLocalOrigin( vec3_origin );
  976. m_hViewmodelAttachment->UpdatePartitionListEntry();
  977. m_hViewmodelAttachment->CollisionProp()->UpdatePartition();
  978. m_hViewmodelAttachment->UpdateVisibility();
  979. m_bAttachmentDirty = true;
  980. }
  981. }
  982. else if ( m_hViewmodelAttachment )
  983. {
  984. // If a player changes team, we may need to update the skin on the attachment weapon model
  985. if ( m_iOldTeam != m_iTeamNum )
  986. {
  987. m_bAttachmentDirty = true;
  988. }
  989. }
  990. // We can't pull data from the viewmodel until we're actually the active weapon.
  991. if ( m_bAttachmentDirty && m_hViewmodelAttachment )
  992. {
  993. pOwner = ToBasePlayer( GetOwnerEntity() );
  994. C_BaseViewModel *vm = pOwner->GetViewModel( 0 );
  995. if ( vm && vm->GetWeapon() == this )
  996. {
  997. m_hViewmodelAttachment->m_nSkin = vm->GetSkin();
  998. m_bAttachmentDirty = false;
  999. }
  1000. }
  1001. return;
  1002. }
  1003. }
  1004. // If we get here we shouldn't have an attachment.
  1005. if ( m_hViewmodelAttachment )
  1006. {
  1007. m_hViewmodelAttachment->Release();
  1008. }
  1009. #endif // !defined( DOTA_DLL )
  1010. }
  1011. //-----------------------------------------------------------------------------
  1012. // Purpose:
  1013. //-----------------------------------------------------------------------------
  1014. bool CEconEntity::HasCustomParticleSystems( void ) const
  1015. {
  1016. return m_bHasParticleSystems;
  1017. }
  1018. //-----------------------------------------------------------------z------------
  1019. // Purpose: Create / Destroy particle systems on this item as appropriate
  1020. //-----------------------------------------------------------------------------
  1021. void CEconEntity::UpdateParticleSystems( void )
  1022. {
  1023. if ( !HasCustomParticleSystems() )
  1024. return;
  1025. ParticleSystemState_t nVisible = PARTICLE_SYSTEM_STATE_NOT_VISIBLE;
  1026. if ( IsEffectActive( EF_NODRAW ) || !ShouldDraw() )
  1027. {
  1028. nVisible = PARTICLE_SYSTEM_STATE_NOT_VISIBLE;
  1029. }
  1030. else if ( !GetOwnerEntity() && !IsDormant() )
  1031. {
  1032. nVisible = PARTICLE_SYSTEM_STATE_VISIBLE;
  1033. }
  1034. else if ( GetOwnerEntity() && !GetOwnerEntity()->IsDormant() && GetOwnerEntity()->IsPlayer() && GetOwnerEntity()->IsAlive() )
  1035. {
  1036. nVisible = PARTICLE_SYSTEM_STATE_VISIBLE;
  1037. }
  1038. if ( nVisible == PARTICLE_SYSTEM_STATE_NOT_VISIBLE )
  1039. {
  1040. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  1041. // Make sure the entity we're attaching to is being drawn
  1042. CTFWeaponBase *pWeapon = dynamic_cast< CTFWeaponBase* >( this );
  1043. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1044. if ( pLocalPlayer && pLocalPlayer == GetOwnerEntity() && pLocalPlayer->GetViewModel() && pLocalPlayer->GetViewModel()->GetWeapon() == pWeapon && !C_BasePlayer::ShouldDrawLocalPlayer() )
  1045. {
  1046. nVisible = PARTICLE_SYSTEM_STATE_VISIBLE_VM;
  1047. }
  1048. #endif
  1049. }
  1050. if ( nVisible != PARTICLE_SYSTEM_STATE_NOT_VISIBLE && !ShouldDrawParticleSystems() )
  1051. {
  1052. nVisible = PARTICLE_SYSTEM_STATE_NOT_VISIBLE;
  1053. }
  1054. SetParticleSystemsVisible( nVisible );
  1055. }
  1056. //-----------------------------------------------------------------------------
  1057. // Purpose:
  1058. //-----------------------------------------------------------------------------
  1059. bool CEconEntity::ShouldDrawParticleSystems( void )
  1060. {
  1061. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  1062. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  1063. if ( pPlayer )
  1064. {
  1065. bool bStealthed = pPlayer->m_Shared.IsStealthed();
  1066. if ( bStealthed )
  1067. return false;
  1068. bool bDisguised = pPlayer->m_Shared.InCond( TF_COND_DISGUISED );
  1069. if ( bDisguised )
  1070. {
  1071. CTFWeaponBase *pWeapon = dynamic_cast<CTFWeaponBase*>( this );
  1072. bool bDisguiseWeapon = pWeapon && pWeapon->m_bDisguiseWeapon;
  1073. if ( !bDisguiseWeapon )
  1074. {
  1075. return false;
  1076. }
  1077. }
  1078. }
  1079. #endif
  1080. // Make sure the entity we're attaching to is being drawn
  1081. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1082. if ( pLocalPlayer )
  1083. {
  1084. C_BaseEntity *pEffectOwner = this;
  1085. if ( pLocalPlayer == GetOwnerEntity() && pLocalPlayer->GetViewModel() && !C_BasePlayer::ShouldDrawLocalPlayer() )
  1086. {
  1087. pEffectOwner = pLocalPlayer->GetViewModel();
  1088. }
  1089. if ( !pEffectOwner->ShouldDraw() )
  1090. {
  1091. return false;
  1092. }
  1093. }
  1094. return true;
  1095. }
  1096. //-----------------------------------------------------------------------------
  1097. // Purpose:
  1098. //-----------------------------------------------------------------------------
  1099. void CEconEntity::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  1100. {
  1101. if ( !InternalFireEvent( origin, angles, event, options ) )
  1102. {
  1103. BaseClass::FireEvent( origin, angles, event, options );
  1104. }
  1105. }
  1106. //-----------------------------------------------------------------------------
  1107. // Purpose:
  1108. //-----------------------------------------------------------------------------
  1109. bool CEconEntity::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
  1110. {
  1111. return InternalFireEvent( origin, angles, event, options );
  1112. }
  1113. //-----------------------------------------------------------------------------
  1114. // Purpose:
  1115. //-----------------------------------------------------------------------------
  1116. bool CEconEntity::InternalFireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  1117. {
  1118. switch( event )
  1119. {
  1120. case AE_CL_BODYGROUP_SET_VALUE_CMODEL_WPN:
  1121. if ( m_hViewmodelAttachment )
  1122. {
  1123. // Translate it into a set bodygroup event on our attached weapon
  1124. m_hViewmodelAttachment->FireEvent( origin, angles, AE_CL_BODYGROUP_SET_VALUE, options );
  1125. }
  1126. return true;
  1127. break;
  1128. }
  1129. return false;
  1130. }
  1131. //-----------------------------------------------------------------------------
  1132. // Purpose: Does this model use delayed flex weights?
  1133. //-----------------------------------------------------------------------------
  1134. bool CEconEntity::UsesFlexDelayedWeights()
  1135. {
  1136. return m_flFlexDelayedWeight != NULL;
  1137. }
  1138. //-----------------------------------------------------------------------------
  1139. // Purpose: Rendering callback to allow the client to set up all the model specific flex weights
  1140. //-----------------------------------------------------------------------------
  1141. void CEconEntity::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
  1142. {
  1143. if ( GetModelPtr() && GetModelPtr()->numflexcontrollers() )
  1144. {
  1145. if ( IsEffectActive( EF_BONEMERGE ) && GetMoveParent() )
  1146. {
  1147. C_BaseFlex *pParentFlex = dynamic_cast<C_BaseFlex*>( GetMoveParent() );
  1148. if ( pParentFlex )
  1149. {
  1150. // BUGBUG: We have a bug with SetCustomModel that causes a disagreement between the studio header here and the one used in l_studio.cpp CModelRender::DrawModelExecute
  1151. // So when we hit that case, let's not do any work because otherwise we'd crash since the array sizes (m_flFlexDelayedWeight vs pFlexWeights) don't match.
  1152. // Note that this check is duplicated in C_BaseFlex::SetupLocalWeights.
  1153. AssertMsg( nFlexWeightCount == m_cFlexDelayedWeight, "Disagreement between the number of flex weights. Do the studio headers match?" );
  1154. if ( nFlexWeightCount != m_cFlexDelayedWeight )
  1155. {
  1156. return;
  1157. }
  1158. if ( pParentFlex->SetupGlobalWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights ) )
  1159. {
  1160. // convert the flex controllers into actual flex values
  1161. C_BaseFlex::RunFlexRules( GetModelPtr(), pFlexWeights );
  1162. // aim the eyes
  1163. // SetViewTarget( hdr ); // FIXME: Not enough info yet
  1164. // process local versions of the delay weights
  1165. if ( pFlexDelayedWeights )
  1166. {
  1167. C_BaseFlex::RunFlexDelay( nFlexWeightCount, pFlexWeights, m_flFlexDelayedWeight, m_flFlexDelayTime );
  1168. memcpy( pFlexDelayedWeights, m_flFlexDelayedWeight, sizeof( float ) * nFlexWeightCount );
  1169. }
  1170. return;
  1171. }
  1172. }
  1173. }
  1174. }
  1175. BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
  1176. return;
  1177. }
  1178. //-----------------------------------------------------------------------------
  1179. // Purpose:
  1180. //-----------------------------------------------------------------------------
  1181. static void cc_dump_particlemanifest()
  1182. {
  1183. Msg("Dumping particle list:\n");
  1184. for ( int i = 0; i < g_pParticleSystemMgr->GetParticleSystemCount(); i++ )
  1185. {
  1186. const char *pParticleSystemName = g_pParticleSystemMgr->GetParticleSystemNameFromIndex(i);
  1187. Msg(" %d: %s\n", i, pParticleSystemName );
  1188. }
  1189. }
  1190. static ConCommand dump_particlemanifest( "dump_particlemanifest", cc_dump_particlemanifest, "Dump the list of particles loaded.", FCVAR_CHEAT );
  1191. //-----------------------------------------------------------------------------
  1192. // Purpose:
  1193. //-----------------------------------------------------------------------------
  1194. void CEconEntity::GetEconParticleSystems( CUtlVector<const attachedparticlesystem_t *> *out_pvecParticleSystems ) const
  1195. {
  1196. Assert( out_pvecParticleSystems );
  1197. const CEconItemView *pEconItemView = m_AttributeManager.GetItem();
  1198. if ( pEconItemView )
  1199. {
  1200. const GameItemDefinition_t *pItemDef = pEconItemView->GetStaticData();
  1201. // Count static particles included in the item definition -- these are things like
  1202. // the kritzkrieg particles or the milk splash particles.
  1203. const int iStaticParticleCount = pItemDef->GetNumAttachedParticles( GetTeamNumber() );
  1204. for ( int i = 0; i < iStaticParticleCount; i++ )
  1205. {
  1206. out_pvecParticleSystems->AddToTail( pItemDef->GetAttachedParticleData( GetTeamNumber(), i ) );
  1207. }
  1208. // Do we have a particle effect that goes along with our specific quality? Self-made
  1209. // and community items have a sparkle, for example.
  1210. const int iQualityParticleType = pEconItemView->GetQualityParticleType();
  1211. if ( iQualityParticleType > 0 )
  1212. {
  1213. out_pvecParticleSystems->AddToTail( GetItemSchema()->GetAttributeControlledParticleSystem( iQualityParticleType ) );
  1214. }
  1215. }
  1216. // Do we have particle systems added on via static attributes (ie., pipe smoke)?
  1217. // Note that this is functionally identical to the dynamic unusual particles. We don't support
  1218. // having multiple attributes of the same type with independent values so we split these out
  1219. // at a higher level, limiting ourself to one of each.
  1220. int iStaticParticleEffect = 0;
  1221. CALL_ATTRIB_HOOK_INT( iStaticParticleEffect, set_attached_particle_static );
  1222. if ( iStaticParticleEffect > 0 )
  1223. {
  1224. out_pvecParticleSystems->AddToTail( GetItemSchema()->GetAttributeControlledParticleSystem( iStaticParticleEffect ) );
  1225. }
  1226. // Do we have particle systems added on dynamically (ie., unusuals?)?
  1227. int iDynamicParticleEffect = 0;
  1228. int iIsThrowableTrail = 0;
  1229. CALL_ATTRIB_HOOK_INT( iDynamicParticleEffect, set_attached_particle );
  1230. CALL_ATTRIB_HOOK_INT( iIsThrowableTrail, throwable_particle_trail_only );
  1231. #if defined(TF_CLIENT_DLL)
  1232. #ifdef STAGING_ONLY
  1233. if ( pEconItemView )
  1234. {
  1235. const GameItemDefinition_t *pItemDef = pEconItemView->GetStaticData();
  1236. int iSlot = pItemDef->GetLoadoutSlot( 0 );
  1237. if ( unusual_force_weapon_effect.GetInt() > 0 )
  1238. {
  1239. if ( iSlot == LOADOUT_POSITION_PRIMARY || iSlot == LOADOUT_POSITION_SECONDARY || iSlot == LOADOUT_POSITION_MELEE )
  1240. {
  1241. iDynamicParticleEffect = unusual_force_weapon_effect.GetInt();
  1242. }
  1243. }
  1244. if ( unusual_force_cosmetic_effect.GetInt() > 0 )
  1245. {
  1246. if ( iSlot == LOADOUT_POSITION_MISC )
  1247. {
  1248. iDynamicParticleEffect = unusual_force_cosmetic_effect.GetInt();
  1249. }
  1250. }
  1251. }
  1252. #endif
  1253. #endif
  1254. if ( iDynamicParticleEffect > 0 && !iIsThrowableTrail )
  1255. {
  1256. attachedparticlesystem_t *pSystem = GetItemSchema()->GetAttributeControlledParticleSystem( iDynamicParticleEffect );
  1257. if ( pSystem )
  1258. {
  1259. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  1260. // TF Team Color Particles
  1261. static char pszFullname[256];
  1262. if ( GetTeamNumber() == TF_TEAM_BLUE && V_stristr( pSystem->pszSystemName, "_teamcolor_red" ))
  1263. {
  1264. V_StrSubst( pSystem->pszSystemName, "_teamcolor_red", "_teamcolor_blue", pszFullname, 256 );
  1265. pSystem = GetItemSchema()->FindAttributeControlledParticleSystem( pszFullname );
  1266. }
  1267. else if ( GetTeamNumber() == TF_TEAM_RED && V_stristr( pSystem->pszSystemName, "_teamcolor_blue" ))
  1268. {
  1269. // Guard against accidentally giving out the blue team color (support tool)
  1270. V_StrSubst( pSystem->pszSystemName, "_teamcolor_blue", "_teamcolor_red", pszFullname, 256 );
  1271. pSystem = GetItemSchema()->FindAttributeControlledParticleSystem( pszFullname );
  1272. }
  1273. #endif
  1274. if ( pSystem )
  1275. {
  1276. out_pvecParticleSystems->AddToTail( pSystem );
  1277. }
  1278. }
  1279. }
  1280. // Scan the particle system
  1281. // - Clean up our list in case we fed in bad data from the schema or wherever.
  1282. for ( int i = out_pvecParticleSystems->Count() - 1; i >= 0; i-- )
  1283. {
  1284. if ( !(*out_pvecParticleSystems)[i] ||
  1285. !(*out_pvecParticleSystems)[i]->pszSystemName ||
  1286. !(*out_pvecParticleSystems)[i]->pszSystemName[0] )
  1287. {
  1288. out_pvecParticleSystems->FastRemove( i );
  1289. }
  1290. }
  1291. }
  1292. //-----------------------------------------------------------------------------
  1293. // Purpose:
  1294. //-----------------------------------------------------------------------------
  1295. void CEconEntity::SetParticleSystemsVisible( ParticleSystemState_t nState )
  1296. {
  1297. if ( nState == m_nParticleSystemsCreated )
  1298. {
  1299. bool bDirty = false;
  1300. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  1301. CTFWeaponBase *pWeapon = dynamic_cast< CTFWeaponBase* >( this );
  1302. if ( pWeapon )
  1303. {
  1304. if ( pWeapon->m_hExtraWearable.Get() )
  1305. {
  1306. bDirty = !( pWeapon->m_hExtraWearable->m_nParticleSystemsCreated == nState );
  1307. pWeapon->m_hExtraWearable->m_nParticleSystemsCreated = nState;
  1308. }
  1309. if ( pWeapon->m_hExtraWearableViewModel.Get() )
  1310. {
  1311. bDirty = !( pWeapon->m_hExtraWearableViewModel->m_nParticleSystemsCreated == nState );
  1312. pWeapon->m_hExtraWearableViewModel->m_nParticleSystemsCreated = nState;
  1313. }
  1314. }
  1315. #endif
  1316. if ( !bDirty )
  1317. {
  1318. return;
  1319. }
  1320. }
  1321. CUtlVector<const attachedparticlesystem_t *> vecParticleSystems;
  1322. GetEconParticleSystems( &vecParticleSystems );
  1323. FOR_EACH_VEC( vecParticleSystems, i )
  1324. {
  1325. const attachedparticlesystem_t *pSystem = vecParticleSystems[i];
  1326. Assert( pSystem );
  1327. Assert( pSystem->pszSystemName );
  1328. Assert( pSystem->pszSystemName[0] );
  1329. // Ignore custom particles. Weapons handle them in custom fashions.
  1330. if ( pSystem->iCustomType )
  1331. continue;
  1332. UpdateSingleParticleSystem( nState != PARTICLE_SYSTEM_STATE_NOT_VISIBLE, pSystem );
  1333. }
  1334. m_nParticleSystemsCreated = nState;
  1335. }
  1336. //-----------------------------------------------------------------------------
  1337. // Purpose:
  1338. //-----------------------------------------------------------------------------
  1339. void CEconEntity::UpdateSingleParticleSystem( bool bVisible, const attachedparticlesystem_t *pSystem )
  1340. {
  1341. Assert( pSystem );
  1342. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1343. if ( !pLocalPlayer )
  1344. return;
  1345. C_BaseEntity *pEffectOwnerWM = this;
  1346. C_BaseEntity *pEffectOwnerVM = NULL;
  1347. bool bExtraWearable = false;
  1348. bool bExtraWearableVM = false;
  1349. CTFWeaponBase *pWeapon = dynamic_cast< CTFWeaponBase* >( this );
  1350. if ( pWeapon )
  1351. {
  1352. pEffectOwnerVM = pWeapon->GetPlayerOwner() ? pWeapon->GetPlayerOwner()->GetViewModel() : NULL;
  1353. if ( pWeapon->m_hExtraWearable.Get() )
  1354. {
  1355. pEffectOwnerWM = pWeapon->m_hExtraWearable.Get();
  1356. bExtraWearable = true;
  1357. }
  1358. if ( pWeapon->m_hExtraWearableViewModel.Get() )
  1359. {
  1360. pEffectOwnerVM = pWeapon->m_hExtraWearableViewModel.Get();
  1361. bExtraWearableVM = true;
  1362. }
  1363. }
  1364. C_BaseEntity *pEffectOwner = pEffectOwnerWM;
  1365. bool bIsVM = false;
  1366. C_BasePlayer *pOwner = ToBasePlayer(GetOwnerEntity());
  1367. bool bDrawThisEffect = true;
  1368. if ( !pOwner->ShouldDrawThisPlayer() )
  1369. {
  1370. // only draw effects designated for this
  1371. if ( !pSystem->bDrawInViewModel )
  1372. {
  1373. bDrawThisEffect = false;
  1374. }
  1375. C_BaseViewModel *pLocalPlayerVM = pLocalPlayer->GetViewModel();
  1376. if ( pLocalPlayerVM && pLocalPlayerVM->GetOwningWeapon() == this )
  1377. {
  1378. bIsVM = true;
  1379. pEffectOwner = pEffectOwnerVM;
  1380. }
  1381. }
  1382. const char *pszAttachmentName = pSystem->pszControlPoints[0];
  1383. if ( bIsVM && bExtraWearableVM )
  1384. pszAttachmentName = "attach_fob_v";
  1385. if ( !bIsVM && bExtraWearable )
  1386. pszAttachmentName = "attach_fob";
  1387. int iAttachment = INVALID_PARTICLE_ATTACHMENT;
  1388. if ( pszAttachmentName && pszAttachmentName[0] && pEffectOwner->GetBaseAnimating() )
  1389. {
  1390. iAttachment = pEffectOwner->GetBaseAnimating()->LookupAttachment( pszAttachmentName );
  1391. }
  1392. // Stop it on both the viewmodel & the world model, because it may be removed due to first/thirdperson switch
  1393. // Get Full name
  1394. const CEconItemView *pEconItemView = m_AttributeManager.GetItem();
  1395. static char pszTempName[256];
  1396. static char pszTempNameVM[256];
  1397. const char* pszSystemName = pSystem->pszSystemName;
  1398. // Weapon Remap for a Base Effect to be used on a specific weapon
  1399. if ( pSystem->bUseSuffixName && pEconItemView && pEconItemView->GetItemDefinition()->GetParticleSuffix() )
  1400. {
  1401. V_strcpy_safe( pszTempName, pszSystemName );
  1402. V_strcat_safe( pszTempName, "_" );
  1403. V_strcat_safe( pszTempName, pEconItemView->GetItemDefinition()->GetParticleSuffix() );
  1404. pszSystemName = pszTempName;
  1405. }
  1406. if ( pSystem->bHasViewModelSpecificEffect )
  1407. {
  1408. V_strcpy_safe( pszTempNameVM, pszSystemName );
  1409. V_strcat_safe( pszTempNameVM, "_vm" );
  1410. // VM doesnt exist so fall back to regular
  1411. if ( g_pParticleSystemMgr->FindParticleSystem( pszTempNameVM ) == NULL )
  1412. {
  1413. V_strcpy_safe( pszTempNameVM, pszSystemName );
  1414. }
  1415. if ( bIsVM )
  1416. {
  1417. pszSystemName = pszTempNameVM;
  1418. }
  1419. }
  1420. // Check that the effect is valid
  1421. if ( g_pParticleSystemMgr->FindParticleSystem( pszSystemName ) == NULL )
  1422. return;
  1423. if ( iAttachment != INVALID_PARTICLE_ATTACHMENT )
  1424. {
  1425. pEffectOwnerWM->ParticleProp()->StopParticlesWithNameAndAttachment( pszSystemName, iAttachment, true );
  1426. if ( pEffectOwnerVM )
  1427. {
  1428. if ( pSystem->bHasViewModelSpecificEffect )
  1429. {
  1430. pEffectOwnerVM->ParticleProp()->StopParticlesWithNameAndAttachment( pszTempNameVM, iAttachment, true );
  1431. }
  1432. pEffectOwnerVM->ParticleProp()->StopParticlesWithNameAndAttachment( pszSystemName, iAttachment, true );
  1433. }
  1434. }
  1435. else
  1436. {
  1437. pEffectOwnerWM->ParticleProp()->StopParticlesNamed( pszSystemName, true );
  1438. if ( pEffectOwnerVM )
  1439. {
  1440. if ( pSystem->bHasViewModelSpecificEffect )
  1441. {
  1442. pEffectOwnerVM->ParticleProp()->StopParticlesNamed( pszTempNameVM, true );
  1443. }
  1444. pEffectOwnerVM->ParticleProp()->StopParticlesNamed( pszSystemName, true );
  1445. }
  1446. }
  1447. if ( !bDrawThisEffect )
  1448. return;
  1449. // do not generate a viewmodel effect if there is no weapon else it is in your face
  1450. if ( !pWeapon && bIsVM )
  1451. {
  1452. Assert( 0 );
  1453. Warning( "Cannot create a Viewmodel Particle Effect [%s] when there is no Viewmodel Weapon", pszSystemName );
  1454. return;
  1455. }
  1456. if ( bVisible && pEffectOwner )
  1457. {
  1458. HPARTICLEFFECT pEffect = NULL;
  1459. // We can't have fastcull on if we want particles attached to us
  1460. //if ( !bIsVM )
  1461. {
  1462. RemoveEffects( EF_BONEMERGE_FASTCULL );
  1463. }
  1464. if ( iAttachment != INVALID_PARTICLE_ATTACHMENT )
  1465. {
  1466. pEffect = pEffectOwner->ParticleProp()->Create( pszSystemName, PATTACH_POINT_FOLLOW, pszAttachmentName );
  1467. }
  1468. else
  1469. {
  1470. // Attachments can fall back to following root bones if the attachment point wasn't found
  1471. if ( pSystem->bFollowRootBone )
  1472. {
  1473. pEffect = pEffectOwner->ParticleProp()->Create( pszSystemName, PATTACH_ROOTBONE_FOLLOW );
  1474. }
  1475. else
  1476. {
  1477. pEffect = pEffectOwner->ParticleProp()->Create( pszSystemName, PATTACH_ABSORIGIN_FOLLOW );
  1478. }
  1479. }
  1480. if ( pEffect )
  1481. {
  1482. // update the control points if necessary
  1483. for ( int i=1; i<ARRAYSIZE( pSystem->pszControlPoints ); ++i )
  1484. {
  1485. const char *pszControlPointName = pSystem->pszControlPoints[i];
  1486. if ( pszControlPointName && pszControlPointName[0] != '\0' )
  1487. {
  1488. pEffectOwner->ParticleProp()->AddControlPoint( pEffect, i, this, PATTACH_POINT_FOLLOW, pszControlPointName );
  1489. }
  1490. }
  1491. if ( bIsVM )
  1492. {
  1493. pEffect->SetIsViewModelEffect( true );
  1494. ClientLeafSystem()->SetRenderGroup( pEffect->RenderHandle(), RENDER_GROUP_VIEW_MODEL_TRANSLUCENT );
  1495. }
  1496. }
  1497. }
  1498. }
  1499. //-----------------------------------------------------------------------------
  1500. // Purpose:
  1501. //-----------------------------------------------------------------------------
  1502. bool CEconEntity::InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup )
  1503. {
  1504. m_bClientside = true;
  1505. return BaseClass::InitializeAsClientEntity( pszModelName, renderGroup );
  1506. }
  1507. //-----------------------------------------------------------------------------
  1508. // Purpose: Get an econ material override for the given team.
  1509. // Returns: NULL if there is no override.
  1510. //-----------------------------------------------------------------------------
  1511. IMaterial* CEconEntity::GetEconWeaponMaterialOverride( int iTeam )
  1512. {
  1513. if ( iTeam >= 0 && iTeam < TEAM_VISUAL_SECTIONS && m_MaterialOverrides[ iTeam ].IsValid() )
  1514. return m_MaterialOverrides[ iTeam ];
  1515. return NULL;
  1516. }
  1517. bool CEconEntity::ShouldDraw()
  1518. {
  1519. if ( ShouldHideForVisionFilterFlags() )
  1520. {
  1521. return false;
  1522. }
  1523. return BaseClass::ShouldDraw();
  1524. }
  1525. bool CEconEntity::ShouldHideForVisionFilterFlags( void )
  1526. {
  1527. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  1528. if ( pItem && pItem->IsValid() )
  1529. {
  1530. CEconItemDefinition *pData = pItem->GetStaticData();
  1531. if ( pData )
  1532. {
  1533. int nVisionFilterFlags = pData->GetVisionFilterFlags();
  1534. if ( nVisionFilterFlags != 0 )
  1535. {
  1536. // Only visible if the local player has an item that allows them to see it (Pyro Goggles)
  1537. if ( !IsLocalPlayerUsingVisionFilterFlags( nVisionFilterFlags, true ) )
  1538. {
  1539. // They didn't have the correct vision flags
  1540. return true;
  1541. }
  1542. }
  1543. }
  1544. }
  1545. return false;
  1546. }
  1547. bool CEconEntity::IsTransparent( void )
  1548. {
  1549. #ifdef TF_CLIENT_DLL
  1550. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  1551. if ( pPlayer )
  1552. {
  1553. return pPlayer->IsTransparent();
  1554. }
  1555. #endif // TF_CLIENT_DLL
  1556. return BaseClass::IsTransparent();
  1557. }
  1558. //-----------------------------------------------------------------------------
  1559. // Purpose:
  1560. //-----------------------------------------------------------------------------
  1561. bool CEconEntity::ViewModel_IsTransparent( void )
  1562. {
  1563. if ( m_hViewmodelAttachment != NULL && m_hViewmodelAttachment->IsTransparent() )
  1564. {
  1565. return true;
  1566. }
  1567. return IsTransparent();
  1568. }
  1569. //-----------------------------------------------------------------------------
  1570. // Purpose:
  1571. //-----------------------------------------------------------------------------
  1572. bool CEconEntity::ViewModel_IsUsingFBTexture( void )
  1573. {
  1574. if ( m_hViewmodelAttachment != NULL && m_hViewmodelAttachment->UsesPowerOfTwoFrameBufferTexture() )
  1575. {
  1576. return true;
  1577. }
  1578. return UsesPowerOfTwoFrameBufferTexture();
  1579. }
  1580. //-----------------------------------------------------------------------------
  1581. // Purpose:
  1582. //-----------------------------------------------------------------------------
  1583. bool CEconEntity::IsOverridingViewmodel( void )
  1584. {
  1585. bool bUseOverride = (GetTeamNumber() >= 0 && GetTeamNumber() < TEAM_VISUAL_SECTIONS) && m_MaterialOverrides[GetTeamNumber()].IsValid();
  1586. bUseOverride = bUseOverride || (m_hViewmodelAttachment != NULL) || ( m_AttributeManager.GetItem()->GetStaticData()->GetNumAttachedModels( GetTeamNumber() ) > 0 );
  1587. return bUseOverride;
  1588. }
  1589. //-----------------------------------------------------------------------------
  1590. // Purpose:
  1591. //-----------------------------------------------------------------------------
  1592. int CEconEntity::DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags )
  1593. {
  1594. int ret = 0;
  1595. #ifndef DOTA_DLL
  1596. bool bIsAttachmentTranslucent = m_hViewmodelAttachment.Get() ? m_hViewmodelAttachment->IsTransparent() : false;
  1597. bool bUseOverride = false;
  1598. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  1599. bool bAttachesToHands = ( pItem->IsValid() && (pItem->GetStaticData()->ShouldAttachToHands() || pItem->GetStaticData()->ShouldAttachToHandsVMOnly()));
  1600. // If the attachment is translucent, we need to render the viewmodel first
  1601. if ( bIsAttachmentTranslucent )
  1602. {
  1603. ret = pViewmodel->DrawOverriddenViewmodel( flags );
  1604. }
  1605. if ( flags & STUDIO_RENDER )
  1606. {
  1607. // If there is some other material override, it's probably the client asking for us to render invuln or the
  1608. // spy cloaking. Those are way more important than ours, so do them instead.
  1609. IMaterial* pOverrideMaterial = NULL;
  1610. OverrideType_t nDontcare = OVERRIDE_NORMAL;
  1611. modelrender->GetMaterialOverride( &pOverrideMaterial, &nDontcare );
  1612. bool bIgnoreOverride = pOverrideMaterial != NULL;
  1613. bUseOverride = !bIgnoreOverride && (GetTeamNumber() >= 0 && GetTeamNumber() < TEAM_VISUAL_SECTIONS) && m_MaterialOverrides[GetTeamNumber()].IsValid();
  1614. if ( bUseOverride )
  1615. {
  1616. modelrender->ForcedMaterialOverride( m_MaterialOverrides[GetTeamNumber()] );
  1617. flags |= STUDIO_NO_OVERRIDE_FOR_ATTACH;
  1618. }
  1619. if ( m_hViewmodelAttachment )
  1620. {
  1621. m_hViewmodelAttachment->RemoveEffects( EF_NODRAW );
  1622. m_hViewmodelAttachment->DrawModel( flags );
  1623. m_hViewmodelAttachment->AddEffects( EF_NODRAW );
  1624. }
  1625. // if we are attached to the hands, then we DO NOT want have an override material when we draw our view model
  1626. if ( bAttachesToHands && bUseOverride )
  1627. {
  1628. modelrender->ForcedMaterialOverride( NULL );
  1629. bUseOverride = false;
  1630. }
  1631. }
  1632. if ( !bIsAttachmentTranslucent )
  1633. {
  1634. ret = pViewmodel->DrawOverriddenViewmodel( flags );
  1635. }
  1636. if ( bUseOverride )
  1637. {
  1638. modelrender->ForcedMaterialOverride( NULL );
  1639. }
  1640. #endif // !defined( DOTA_DLL )
  1641. return ret;
  1642. }
  1643. //-----------------------------------------------------------------------------
  1644. // Purpose:
  1645. //-----------------------------------------------------------------------------
  1646. bool CEconEntity::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo )
  1647. {
  1648. if ( !BaseClass::OnInternalDrawModel( pInfo ) )
  1649. return false;
  1650. DrawEconEntityAttachedModels( this, this, pInfo, kAttachedModelDisplayFlag_WorldModel );
  1651. return true;
  1652. }
  1653. //-----------------------------------------------------------------------------
  1654. // Purpose:
  1655. //-----------------------------------------------------------------------------
  1656. int CEconEntity::LookupAttachment( const char *pAttachmentName )
  1657. {
  1658. if ( m_hViewmodelAttachment )
  1659. return m_hViewmodelAttachment->LookupAttachment( pAttachmentName );
  1660. return BaseClass::LookupAttachment( pAttachmentName );
  1661. }
  1662. //-----------------------------------------------------------------------------
  1663. // Purpose:
  1664. //-----------------------------------------------------------------------------
  1665. bool CEconEntity::GetAttachment( int number, matrix3x4_t &matrix )
  1666. {
  1667. if ( m_hViewmodelAttachment )
  1668. return m_hViewmodelAttachment->GetAttachment( number, matrix );
  1669. return BaseClass::GetAttachment( number, matrix );
  1670. }
  1671. //-----------------------------------------------------------------------------
  1672. // Purpose:
  1673. //-----------------------------------------------------------------------------
  1674. bool CEconEntity::GetAttachment( int number, Vector &origin )
  1675. {
  1676. if ( m_hViewmodelAttachment )
  1677. return m_hViewmodelAttachment->GetAttachment( number, origin );
  1678. return BaseClass::GetAttachment( number, origin );
  1679. }
  1680. //-----------------------------------------------------------------------------
  1681. // Purpose:
  1682. //-----------------------------------------------------------------------------
  1683. bool CEconEntity::GetAttachment( int number, Vector &origin, QAngle &angles )
  1684. {
  1685. if ( m_hViewmodelAttachment )
  1686. return m_hViewmodelAttachment->GetAttachment( number, origin, angles );
  1687. return BaseClass::GetAttachment( number, origin, angles );
  1688. }
  1689. //-----------------------------------------------------------------------------
  1690. // Purpose:
  1691. //-----------------------------------------------------------------------------
  1692. bool CEconEntity::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
  1693. {
  1694. if ( m_hViewmodelAttachment )
  1695. return m_hViewmodelAttachment->GetAttachmentVelocity( number, originVel, angleVel );
  1696. return BaseClass::GetAttachmentVelocity( number, originVel, angleVel );
  1697. }
  1698. #endif
  1699. //-----------------------------------------------------------------------------
  1700. // Purpose: Hides or shows masked bodygroups associated with this item.
  1701. //-----------------------------------------------------------------------------
  1702. bool CEconEntity::UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState )
  1703. {
  1704. if ( !pOwner )
  1705. return false;
  1706. CAttributeContainer *pCont = GetAttributeContainer();
  1707. if ( !pCont )
  1708. return false;
  1709. CEconItemView *pItem = pCont->GetItem();
  1710. if ( !pItem )
  1711. return false;
  1712. const CEconItemDefinition *pItemDef = pItem->GetItemDefinition();
  1713. if ( !pItemDef )
  1714. return false;
  1715. int iNumBodyGroups = pItemDef->GetNumModifiedBodyGroups( 0 );
  1716. for ( int i=0; i<iNumBodyGroups; ++i )
  1717. {
  1718. int iBody = 0;
  1719. const char *pszBodyGroup = pItemDef->GetModifiedBodyGroup( 0, i, iBody );
  1720. if ( iBody != iState )
  1721. continue;
  1722. int iBodyGroup = pOwner->FindBodygroupByName( pszBodyGroup );
  1723. if ( iBodyGroup == -1 )
  1724. continue;
  1725. pOwner->SetBodygroup( iBodyGroup, iState );
  1726. }
  1727. // Handle per-style bodygroup hiding
  1728. const CEconStyleInfo *pStyle = pItemDef->GetStyleInfo( pItem->GetStyle() );
  1729. if ( pStyle )
  1730. {
  1731. FOR_EACH_VEC( pStyle->GetAdditionalHideBodygroups(), i )
  1732. {
  1733. int iBodyGroup = pOwner->FindBodygroupByName( pStyle->GetAdditionalHideBodygroups()[i] );
  1734. if ( iBodyGroup == -1 )
  1735. continue;
  1736. pOwner->SetBodygroup( iBodyGroup, iState );
  1737. }
  1738. // should we override this model bodygroup
  1739. if ( pStyle->GetBodygroupName() != NULL )
  1740. {
  1741. int iBodyGroup = pOwner->FindBodygroupByName( pStyle->GetBodygroupName() );
  1742. if ( iBodyGroup != -1 )
  1743. {
  1744. SetBodygroup( iBodyGroup, pStyle->GetBodygroupSubmodelIndex() );
  1745. }
  1746. }
  1747. }
  1748. // Handle world model bodygroup overrides
  1749. int iBodyOverride = pItemDef->GetWorldmodelBodygroupOverride( pOwner->GetTeamNumber() );
  1750. int iBodyStateOverride = pItemDef->GetWorldmodelBodygroupStateOverride( pOwner->GetTeamNumber() );
  1751. if ( iBodyOverride > -1 && iBodyStateOverride > -1 )
  1752. {
  1753. pOwner->SetBodygroup( iBodyOverride, iBodyStateOverride );
  1754. }
  1755. // Handle view model bodygroup overrides
  1756. iBodyOverride = pItemDef->GetViewmodelBodygroupOverride( pOwner->GetTeamNumber() );
  1757. iBodyStateOverride = pItemDef->GetViewmodelBodygroupStateOverride( pOwner->GetTeamNumber() );
  1758. if ( iBodyOverride > -1 && iBodyStateOverride > -1 )
  1759. {
  1760. CBasePlayer *pPlayer = ToBasePlayer( pOwner );
  1761. if ( pPlayer )
  1762. {
  1763. CBaseViewModel *pVM = pPlayer->GetViewModel();
  1764. if ( pVM && pVM->GetModelPtr() )
  1765. {
  1766. pVM->SetBodygroup( iBodyOverride, iBodyStateOverride );
  1767. }
  1768. }
  1769. }
  1770. return true;
  1771. }
  1772. //-----------------------------------------------------------------------------
  1773. // Purpose:
  1774. //-----------------------------------------------------------------------------
  1775. CBaseAttributableItem::CBaseAttributableItem()
  1776. {
  1777. }