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.

789 lines
23 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "tf_item_wearable.h"
  8. #include "vcollide_parse.h"
  9. #include "tf_gamerules.h"
  10. #include "animation.h"
  11. #include "basecombatweapon_shared.h"
  12. #ifdef CLIENT_DLL
  13. #include "c_tf_player.h"
  14. #include "model_types.h"
  15. #include "props_shared.h"
  16. #include "tf_mapinfo.h"
  17. #else
  18. #include "tf_player.h"
  19. #endif
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. LINK_ENTITY_TO_CLASS( tf_wearable, CTFWearable );
  23. IMPLEMENT_NETWORKCLASS_ALIASED( TFWearable, DT_TFWearable )
  24. // Network Table --
  25. BEGIN_NETWORK_TABLE( CTFWearable, DT_TFWearable )
  26. #if defined( GAME_DLL )
  27. SendPropBool( SENDINFO( m_bDisguiseWearable ) ),
  28. SendPropEHandle( SENDINFO( m_hWeaponAssociatedWith ) ),
  29. #else
  30. RecvPropBool( RECVINFO( m_bDisguiseWearable ) ),
  31. RecvPropEHandle( RECVINFO( m_hWeaponAssociatedWith ) ),
  32. #endif // GAME_DLL
  33. END_NETWORK_TABLE()
  34. // -- Network Table
  35. // Data Desc --
  36. BEGIN_DATADESC( CTFWearable )
  37. END_DATADESC()
  38. // -- Data Desc
  39. PRECACHE_REGISTER( tf_wearable );
  40. LINK_ENTITY_TO_CLASS( tf_wearable_vm, CTFWearableVM );
  41. IMPLEMENT_NETWORKCLASS_ALIASED( TFWearableVM, DT_TFWearableVM )
  42. BEGIN_NETWORK_TABLE( CTFWearableVM, DT_TFWearableVM )
  43. END_NETWORK_TABLE()
  44. PRECACHE_REGISTER( tf_wearable_vm );
  45. //-----------------------------------------------------------------------------
  46. // SHARED CODE
  47. //-----------------------------------------------------------------------------
  48. CTFWearable::CTFWearable() : CEconWearable()
  49. {
  50. m_bDisguiseWearable = false;
  51. m_hWeaponAssociatedWith = NULL;
  52. #if defined( CLIENT_DLL )
  53. m_eParticleSystemVisibility = kParticleSystemVisibility_Undetermined;
  54. m_nWorldModelIndex = 0;
  55. #endif
  56. };
  57. //-----------------------------------------------------------------------------
  58. // SERVER ONLY CODE
  59. //-----------------------------------------------------------------------------
  60. #if defined( GAME_DLL )
  61. void CTFWearable::Break( void )
  62. {
  63. CPVSFilter filter( GetAbsOrigin() );
  64. UserMessageBegin( filter, "BreakModel" );
  65. WRITE_SHORT( GetModelIndex() );
  66. WRITE_VEC3COORD( GetAbsOrigin() );
  67. WRITE_ANGLES( GetAbsAngles() );
  68. WRITE_SHORT( GetSkin() );
  69. MessageEnd();
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Purpose:
  73. //-----------------------------------------------------------------------------
  74. int CTFWearable::CalculateVisibleClassFor( CBaseCombatCharacter *pPlayer )
  75. {
  76. if ( m_bDisguiseWearable )
  77. {
  78. CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
  79. if ( pTFPlayer )
  80. return pTFPlayer->m_Shared.GetDisguiseClass();
  81. }
  82. return BaseClass::CalculateVisibleClassFor( pPlayer );
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose:
  86. //-----------------------------------------------------------------------------
  87. int CTFWearable::UpdateTransmitState()
  88. {
  89. return SetTransmitState( FL_EDICT_FULLCHECK );
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose:
  93. //-----------------------------------------------------------------------------
  94. int CTFWearable::ShouldTransmit( const CCheckTransmitInfo *pInfo )
  95. {
  96. if ( pInfo->m_pClientEnt && GetOwnerEntity() && CBaseEntity::Instance( pInfo->m_pClientEnt ) == GetOwnerEntity() )
  97. {
  98. return FL_EDICT_ALWAYS;
  99. }
  100. // We have some entities that have no model (ie., "hatless hats") but we still want
  101. // to transmit them down to clients so that the clients can do things like update body
  102. // groups, etc.
  103. return FL_EDICT_PVSCHECK;
  104. }
  105. #endif
  106. #ifdef CLIENT_DLL
  107. ConVar tf_test_hat_bodygroup( "tf_test_hat_bodygroup", "0", 0, "For testing bodygroups on hats." );
  108. #endif
  109. static int CalcBodyGroup( CBaseCombatCharacter* pOwner, CEconItemView *pItem, const char *pBodyGroup, codecontrolledbodygroupdata_t &ccbgd )
  110. {
  111. #ifdef CLIENT_DLL
  112. if ( !Q_strnicmp( ccbgd.pFuncName, "test", ARRAYSIZE( "test" ) ) )
  113. {
  114. return tf_test_hat_bodygroup.GetInt();
  115. }
  116. else if ( !Q_strnicmp( ccbgd.pFuncName, "map_contributor", ARRAYSIZE( "map_contributor" ) ) )
  117. {
  118. int iDonationAmount = MapInfo_GetDonationAmount( pItem->GetAccountID(), engine->GetLevelName() );
  119. return MIN( iDonationAmount / 25, 4 );
  120. }
  121. #endif
  122. return 0;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // CLIENT ONLY CODE
  126. //-----------------------------------------------------------------------------
  127. #if defined( CLIENT_DLL )
  128. extern ConVar tf_playergib_forceup;
  129. //-----------------------------------------------------------------------------
  130. // Receive the BreakModel user message
  131. //-----------------------------------------------------------------------------
  132. void HandleBreakModel( bf_read &msg, bool bCheap )
  133. {
  134. int nModelIndex = (int)msg.ReadShort();
  135. CUtlVector<breakmodel_t> aGibs;
  136. BuildGibList( aGibs, nModelIndex, 1.0f, COLLISION_GROUP_NONE );
  137. if ( !aGibs.Count() )
  138. return;
  139. // Get the origin & angles
  140. Vector vecOrigin;
  141. QAngle vecAngles;
  142. int nSkin = 0;
  143. msg.ReadBitVec3Coord( vecOrigin );
  144. if ( !bCheap )
  145. {
  146. msg.ReadBitAngles( vecAngles );
  147. nSkin = (int)msg.ReadShort();
  148. }
  149. else
  150. {
  151. vecAngles = vec3_angle;
  152. }
  153. // Launch it straight up with some random spread
  154. Vector vecBreakVelocity = Vector(0,0,200);
  155. AngularImpulse angularImpulse( RandomFloat( 0.0f, 120.0f ), RandomFloat( 0.0f, 120.0f ), 0.0 );
  156. breakablepropparams_t breakParams( vecOrigin, vecAngles, vecBreakVelocity, angularImpulse );
  157. breakParams.impactEnergyScale = 1.0f;
  158. breakParams.nDefaultSkin = nSkin;
  159. CreateGibsFromList( aGibs, nModelIndex, NULL, breakParams, NULL, -1 , false, true );
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Receive the BreakModel user message
  163. //-----------------------------------------------------------------------------
  164. void __MsgFunc_BreakModel( bf_read &msg )
  165. {
  166. HandleBreakModel( msg, false );
  167. }
  168. //-----------------------------------------------------------------------------
  169. // Receive the CheapBreakModel user message
  170. //-----------------------------------------------------------------------------
  171. void __MsgFunc_CheapBreakModel( bf_read &msg )
  172. {
  173. HandleBreakModel( msg, true );
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Receive the BreakModel_Pumpkin user message
  177. //-----------------------------------------------------------------------------
  178. void __MsgFunc_BreakModel_Pumpkin( bf_read &msg )
  179. {
  180. int nModelIndex = (int)msg.ReadShort();
  181. CUtlVector<breakmodel_t> aGibs;
  182. BuildGibList( aGibs, nModelIndex, 1.0f, COLLISION_GROUP_NONE );
  183. if ( !aGibs.Count() )
  184. return;
  185. // Get the origin & angles
  186. Vector vecOrigin;
  187. QAngle vecAngles;
  188. msg.ReadBitVec3Coord( vecOrigin );
  189. msg.ReadBitAngles( vecAngles );
  190. // Launch it straight up with some random spread
  191. Vector vecBreakVelocity = Vector(0,0,0);
  192. AngularImpulse angularImpulse( RandomFloat( 0.0f, 120.0f ), RandomFloat( 0.0f, 120.0f ), 0.0 );
  193. breakablepropparams_t breakParams( vecOrigin /*+ Vector(0,0,20)*/, vecAngles, vecBreakVelocity, angularImpulse );
  194. breakParams.impactEnergyScale = 1.0f;
  195. for ( int i=0; i<aGibs.Count(); ++i )
  196. {
  197. aGibs[i].burstScale = 1000.f;
  198. }
  199. CUtlVector<EHANDLE> hSpawnedGibs;
  200. CreateGibsFromList( aGibs, nModelIndex, NULL, breakParams, NULL, -1 , false, true, &hSpawnedGibs );
  201. // Make the base stay low to the ground.
  202. for ( int i=0; i<hSpawnedGibs.Count(); ++i )
  203. {
  204. CBaseEntity *pGib = hSpawnedGibs[i];
  205. if ( pGib )
  206. {
  207. IPhysicsObject *pPhysObj = pGib->VPhysicsGetObject();
  208. if ( pPhysObj )
  209. {
  210. Vector vecVel;
  211. AngularImpulse angImp;
  212. pPhysObj->GetVelocity( &vecVel, &angImp );
  213. vecVel *= 3.0;
  214. if ( i == 3 )
  215. {
  216. vecVel.z = 300;
  217. }
  218. else
  219. {
  220. vecVel.z = 400;
  221. }
  222. pPhysObj->SetVelocity( &vecVel, &angImp );
  223. }
  224. }
  225. }
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose:
  229. //-----------------------------------------------------------------------------
  230. int CTFWearable::InternalDrawModel( int flags )
  231. {
  232. C_TFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );
  233. if ( pOwner && pOwner->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
  234. {
  235. bool bShouldDraw = false;
  236. const CEconItemView *pItem = GetAttributeContainer()->GetItem();
  237. if ( pItem )
  238. {
  239. econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( "ghost_wearable" );
  240. if ( pItem->GetItemDefinition()->HasEconTag( tagHandle ) )
  241. bShouldDraw = true;
  242. }
  243. if ( !bShouldDraw )
  244. return 0;
  245. }
  246. bool bUseInvulnMaterial = ( pOwner && pOwner->m_Shared.IsInvulnerable() &&
  247. ( !pOwner->m_Shared.InCond( TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED ) || gpGlobals->curtime < pOwner->GetLastDamageTime() + 2.0f ) );
  248. if ( bUseInvulnMaterial && (flags & STUDIO_RENDER) )
  249. {
  250. modelrender->ForcedMaterialOverride( *pOwner->GetInvulnMaterialRef() );
  251. }
  252. int ret = BaseClass::InternalDrawModel( flags );
  253. if ( bUseInvulnMaterial && (flags & STUDIO_RENDER) )
  254. {
  255. modelrender->ForcedMaterialOverride( NULL );
  256. }
  257. return ret;
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose:
  261. //-----------------------------------------------------------------------------
  262. bool CTFWearable::ShouldDraw()
  263. {
  264. C_TFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );
  265. if ( pOwner )
  266. {
  267. if ( pOwner->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
  268. {
  269. const CEconItemView *pItem = GetAttributeContainer()->GetItem();
  270. if ( pItem )
  271. {
  272. econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( "ghost_wearable" );
  273. if ( pItem->GetItemDefinition()->HasEconTag( tagHandle ) )
  274. return BaseClass::ShouldDraw();
  275. }
  276. return false;
  277. }
  278. // don't draw cosmetic while sniper is zoom
  279. if ( pOwner == C_TFPlayer::GetLocalTFPlayer() && pOwner->m_Shared.InCond( TF_COND_ZOOMED ) )
  280. return false;
  281. }
  282. // Don't draw 3rd person wearables if our owner is disguised.
  283. if ( pOwner && pOwner->m_Shared.InCond( TF_COND_DISGUISED ) && !IsViewModelWearable() )
  284. {
  285. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  286. if ( m_bDisguiseWearable && pLocalPlayer )
  287. {
  288. int iLocalPlayerTeam = pLocalPlayer->GetTeamNumber();
  289. if ( pLocalPlayer->m_bIsCoaching && pLocalPlayer->m_hStudent )
  290. {
  291. iLocalPlayerTeam = pLocalPlayer->m_hStudent->GetTeamNumber();
  292. }
  293. // This wearable is a part of our disguise -- we might want to draw it.
  294. if ( GetEnemyTeam( pOwner->GetTeamNumber() ) != iLocalPlayerTeam )
  295. {
  296. // The local player is on this spy's team. We don't see the disguise.
  297. return false;
  298. }
  299. else
  300. {
  301. if ( pOwner->m_Shared.GetDisguiseClass() == TF_CLASS_SPY &&
  302. pOwner->m_Shared.GetDisguiseTeam() == iLocalPlayerTeam )
  303. {
  304. // This enemy spy is disguised as a spy on our team, don't draw wearables.
  305. return false;
  306. }
  307. else
  308. {
  309. // The local player is an enemy. Show the disguise wearable.
  310. return BaseClass::ShouldDraw();
  311. }
  312. }
  313. }
  314. return false;
  315. }
  316. else
  317. {
  318. // See if the visibility is controlled by a weapon.
  319. CTFWeaponBase *pWeapon = assert_cast< CTFWeaponBase* >( GetWeaponAssociatedWith() );
  320. if ( pWeapon )
  321. {
  322. // If the weapon isn't active, don't draw
  323. if ( pOwner && pOwner->GetActiveWeapon() != pWeapon )
  324. {
  325. return false;
  326. }
  327. if ( !IsViewModelWearable() )
  328. {
  329. // If it's the 3rd person wearable, don't draw it when the weapon is hidden
  330. if ( !pWeapon->ShouldDraw() )
  331. {
  332. return false;
  333. }
  334. }
  335. // If the weapon is being repurposed for a taunt dont draw.
  336. // The Brutal Legend taunt changes your weapon's model to be the guitar,
  337. // but we dont want things like bot-killer skulls or festive lights
  338. // to continue to draw
  339. if( pWeapon->IsBeingRepurposedForTaunt() )
  340. {
  341. return false;
  342. }
  343. }
  344. return BaseClass::ShouldDraw();
  345. }
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose:
  349. //-----------------------------------------------------------------------------
  350. bool CTFWearable::ShouldDrawParticleSystems( void )
  351. {
  352. if ( !BaseClass::ShouldDrawParticleSystems() )
  353. return false;
  354. C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  355. bool bStealthed = pPlayer->m_Shared.IsStealthed();
  356. // If we're disguised, this ought to only be getting called on disguise wearables,
  357. // otherwise we could get two particles showing at once (disguise wearable + real wearable).
  358. Assert( !pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) || IsDisguiseWearable() );
  359. if ( bStealthed )
  360. {
  361. return false;
  362. }
  363. if ( m_eParticleSystemVisibility == kParticleSystemVisibility_Undetermined )
  364. {
  365. static CSchemaItemDefHandle pItemDef_MapLoverHat( "World Traveler" );
  366. m_eParticleSystemVisibility = kParticleSystemVisibility_Shown;
  367. const CEconItemView *pItem = GetAttributeContainer()->GetItem();
  368. if ( pItem && pItem->GetStaticData() == pItemDef_MapLoverHat )
  369. {
  370. if ( MapInfo_DidPlayerDonate( pItem->GetAccountID(), engine->GetLevelName() ) == false )
  371. {
  372. m_eParticleSystemVisibility = kParticleSystemVisibility_Hidden;
  373. }
  374. }
  375. }
  376. return m_eParticleSystemVisibility == kParticleSystemVisibility_Shown;
  377. }
  378. int CTFWearable::GetWorldModelIndex( void )
  379. {
  380. if ( m_nWorldModelIndex == 0 )
  381. return m_nModelIndex;
  382. static CSchemaItemDefHandle pItemDef_OculusRiftHeadset( "The TF2VRH" );
  383. const CEconItemView *pItem = GetAttributeContainer()->GetItem();
  384. if ( pItem && pItem->GetStaticData() == pItemDef_OculusRiftHeadset )
  385. {
  386. CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
  387. if ( pTFPlayer )
  388. {
  389. if ( pTFPlayer->IsUsingVRHeadset() && pTFPlayer->GetPlayerClass() )
  390. {
  391. const char *pszReplacementModel = pItem->GetStaticData()->GetPlayerDisplayModelAlt( pTFPlayer->GetPlayerClass()->GetClassIndex() );
  392. if ( pszReplacementModel && pszReplacementModel[0] )
  393. {
  394. return modelinfo->GetModelIndex( pszReplacementModel );
  395. }
  396. }
  397. }
  398. }
  399. //*********************************************************************************
  400. // Parachute states
  401. static CSchemaItemDefHandle pItemDef_BaseJumper( "The B.A.S.E. Jumper" );
  402. const int iParachuteOpen = modelinfo->GetModelIndex( "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_pack_open.mdl" );
  403. const int iParachuteClosed = modelinfo->GetModelIndex( "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_pack.mdl" );
  404. if ( m_nModelIndex == iParachuteOpen || m_nModelIndex == iParachuteClosed )
  405. {
  406. CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
  407. if ( pTFPlayer )
  408. {
  409. if ( pTFPlayer->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) )
  410. {
  411. return iParachuteOpen;
  412. }
  413. else
  414. {
  415. return iParachuteClosed;
  416. }
  417. }
  418. }
  419. if ( GameRules() )
  420. {
  421. const char *pBaseName = modelinfo->GetModelName( modelinfo->GetModel( m_nWorldModelIndex ) );
  422. const char *pTranslatedName = GameRules()->TranslateEffectForVisionFilter( "weapons", pBaseName );
  423. if ( pTranslatedName != pBaseName )
  424. {
  425. return modelinfo->GetModelIndex( pTranslatedName );
  426. }
  427. }
  428. return m_nWorldModelIndex;
  429. }
  430. void CTFWearable::ValidateModelIndex( void )
  431. {
  432. m_nModelIndex = GetWorldModelIndex();
  433. BaseClass::ValidateModelIndex();
  434. }
  435. #endif
  436. //-----------------------------------------------------------------------------
  437. // Purpose: Hides or shows masked bodygroups associated with this item.
  438. //-----------------------------------------------------------------------------
  439. bool CTFWearable::UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState )
  440. {
  441. CTFPlayer *pTFOwner = ToTFPlayer( pOwner );
  442. if ( !pTFOwner )
  443. return false;
  444. bool bBaseUpdate = BaseClass::UpdateBodygroups( pOwner, iState );
  445. if ( bBaseUpdate && m_bDisguiseWearable )
  446. {
  447. CEconItemView *pItem = GetAttributeContainer()->GetItem(); // Safe. Checked in base class call.
  448. CTFPlayer *pDisguiseTarget = ToTFPlayer( pTFOwner->m_Shared.GetDisguiseTarget() );
  449. if ( !pDisguiseTarget )
  450. return false;
  451. // Update our disguise bodygroup.
  452. int iDisguiseBody = pTFOwner->m_Shared.GetDisguiseBody();
  453. int iTeam = pTFOwner->m_Shared.GetDisguiseTeam();
  454. int iNumBodyGroups = pItem->GetStaticData()->GetNumModifiedBodyGroups( iTeam );
  455. for ( int i=0; i<iNumBodyGroups; ++i )
  456. {
  457. int iBody = 0;
  458. const char *pszBodyGroup = pItem->GetStaticData()->GetModifiedBodyGroup( iTeam, i, iBody );
  459. int iBodyGroup = pDisguiseTarget->FindBodygroupByName( pszBodyGroup );
  460. if ( iBodyGroup == -1 )
  461. continue;
  462. ::SetBodygroup( pDisguiseTarget->GetModelPtr(), iDisguiseBody, iBodyGroup, iState );
  463. }
  464. pTFOwner->m_Shared.SetDisguiseBody( iDisguiseBody );
  465. }
  466. CEconItemView *pItem = GetAttributeContainer() ? GetAttributeContainer()->GetItem() : NULL;
  467. if ( pItem )
  468. {
  469. int iTeam = pTFOwner->GetTeamNumber();
  470. int iNumBodyGroups = pItem->GetStaticData()->GetNumCodeControlledBodyGroups( iTeam );
  471. for ( int i=0; i<iNumBodyGroups; ++i )
  472. {
  473. codecontrolledbodygroupdata_t ccbgd = { NULL, NULL };
  474. const char *pszBodyGroup = pItem->GetStaticData()->GetCodeControlledBodyGroup( iTeam, i, ccbgd );
  475. int iBodyGroup = FindBodygroupByName( pszBodyGroup );
  476. if ( iBodyGroup != -1 )
  477. {
  478. SetBodygroup( iBodyGroup, CalcBodyGroup( pOwner, pItem, pszBodyGroup, ccbgd ) );
  479. }
  480. }
  481. }
  482. // Additional hidden bodygroups.
  483. for ( int i=0; i<m_HiddenBodyGroups.Count(); ++i )
  484. {
  485. int iBodyGroup = pOwner->FindBodygroupByName( m_HiddenBodyGroups[i] );
  486. if ( iBodyGroup == -1 )
  487. continue;
  488. pOwner->SetBodygroup( iBodyGroup, iState );
  489. }
  490. return true;
  491. }
  492. int CTFWearable::GetSkin()
  493. {
  494. CTFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  495. if ( !pPlayer )
  496. return 0;
  497. int iTeamNumber = pPlayer->GetTeamNumber();
  498. #if defined( CLIENT_DLL )
  499. // Run client-only "is the viewer on the same team as the wielder" logic. Assumed to
  500. // always be false on the server.
  501. CTFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  502. if ( !pLocalPlayer )
  503. return 0;
  504. int iLocalTeam = pLocalPlayer->GetTeamNumber();
  505. // We only show disguise weapon to the enemy team when owner is disguised
  506. bool bUseDisguiseWeapon = ( iTeamNumber != iLocalTeam && iLocalTeam > LAST_SHARED_TEAM );
  507. if ( bUseDisguiseWeapon && pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) )
  508. {
  509. if ( pLocalPlayer != pPlayer )
  510. {
  511. iTeamNumber = pPlayer->m_Shared.GetDisguiseTeam();
  512. }
  513. }
  514. #endif // defined( CLIENT_DLL )
  515. // See if the item wants to override the skin
  516. int nSkin = -1;
  517. CBaseCombatWeapon *pWeapon = assert_cast< CBaseCombatWeapon* >( GetWeaponAssociatedWith() );
  518. if ( pWeapon )
  519. {
  520. CEconItemView *pItem = pWeapon->GetAttributeContainer()->GetItem();
  521. if ( pItem->IsValid() )
  522. {
  523. nSkin = pItem->GetSkin( iTeamNumber ); // if we didn't have custom code, fall back to the item definition
  524. }
  525. }
  526. if ( nSkin != -1 )
  527. {
  528. return nSkin;
  529. }
  530. return BaseClass::GetSkin();
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Purpose:
  534. //-----------------------------------------------------------------------------
  535. void CTFWearable::InternalSetPlayerDisplayModel( void )
  536. {
  537. // Set our model to the player model
  538. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  539. if ( pItem && pItem->IsValid() && pItem->GetStaticData() )
  540. {
  541. if ( pItem->GetStaticData()->IsContentStreamable() )
  542. {
  543. const char *pszPlayerDisplayModelAlt = pItem->GetStaticData()->GetPlayerDisplayModelAlt();
  544. if ( pszPlayerDisplayModelAlt && pszPlayerDisplayModelAlt[0] )
  545. {
  546. modelinfo->RegisterDynamicModel( pszPlayerDisplayModelAlt, IsClient() );
  547. }
  548. }
  549. }
  550. BaseClass::InternalSetPlayerDisplayModel();
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Purpose:
  554. //-----------------------------------------------------------------------------
  555. void CTFWearable::AddHiddenBodyGroup( const char* bodygroup )
  556. {
  557. m_HiddenBodyGroups.AddToHead( bodygroup );
  558. }
  559. //-----------------------------------------------------------------------------
  560. // Purpose:
  561. //-----------------------------------------------------------------------------
  562. void CTFWearable::ReapplyProvision( void )
  563. {
  564. // Disguise wearables never provide
  565. if ( IsDisguiseWearable() )
  566. {
  567. #ifdef GAME_DLL
  568. UpdateModelToClass();
  569. #endif
  570. return;
  571. }
  572. BaseClass::ReapplyProvision();
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Purpose: Attaches the item to the player.
  576. //-----------------------------------------------------------------------------
  577. void CTFWearable::Equip( CBasePlayer* pOwner )
  578. {
  579. BaseClass::Equip( pOwner );
  580. CTFPlayer *pTFPlayer = ToTFPlayer( pOwner );
  581. if ( !pTFPlayer )
  582. return;
  583. int iTeamNumber = pTFPlayer->GetTeamNumber();
  584. if ( m_bDisguiseWearable )
  585. {
  586. iTeamNumber = pTFPlayer->m_Shared.GetDisguiseTeam();
  587. }
  588. ChangeTeam( iTeamNumber );
  589. m_nSkin = ( iTeamNumber == (LAST_SHARED_TEAM+1) ) ? 0 : 1;
  590. #ifdef CLIENT_DLL
  591. pTFPlayer->SetBodygroupsDirty();
  592. #endif
  593. #ifdef GAME_DLL
  594. // Reapply upgrades for wearables upon equip
  595. CEconItemView *pItem = ( (CTFWearable *)this )->GetAttributeContainer()->GetItem();
  596. if ( pTFPlayer && pItem->IsValid() )
  597. {
  598. pTFPlayer->ReapplyItemUpgrades( pItem );
  599. }
  600. #endif // GAME_DLL
  601. }
  602. //-----------------------------------------------------------------------------
  603. // Purpose: Attaches the item to the player.
  604. //-----------------------------------------------------------------------------
  605. void CTFWearable::UnEquip( CBasePlayer* pOwner )
  606. {
  607. BaseClass::UnEquip( pOwner );
  608. #ifdef CLIENT_DLL
  609. CTFPlayer *pTFPlayer = ToTFPlayer( pOwner );
  610. if ( pTFPlayer )
  611. {
  612. pTFPlayer->SetBodygroupsDirty();
  613. }
  614. #endif
  615. }
  616. //-----------------------------------------------------------------------------
  617. // Purpose: Check for any TF specific restrictions on item use.
  618. //-----------------------------------------------------------------------------
  619. bool CTFWearable::CanEquip( CBaseEntity *pOther )
  620. {
  621. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  622. if ( pItem && TFGameRules() )
  623. {
  624. CEconItemDefinition* pData = pItem->GetStaticData();
  625. if ( pData && pData->GetHolidayRestriction() )
  626. {
  627. int iHolidayRestriction = UTIL_GetHolidayForString( pData->GetHolidayRestriction() );
  628. if ( iHolidayRestriction != kHoliday_None && !TFGameRules()->IsHolidayActive( iHolidayRestriction ) )
  629. return false;
  630. }
  631. }
  632. return true;
  633. }
  634. #ifdef CLIENT_DLL
  635. //-----------------------------------------------------------------------------
  636. // Purpose:
  637. //-----------------------------------------------------------------------------
  638. void CTFWearable::OnDataChanged( DataUpdateType_t updateType )
  639. {
  640. BaseClass::OnDataChanged( updateType );
  641. if ( updateType == DATA_UPDATE_CREATED )
  642. {
  643. ListenForGameEvent( "localplayer_changeteam" );
  644. m_nWorldModelIndex = m_nModelIndex;
  645. }
  646. }
  647. //-----------------------------------------------------------------------------
  648. // Purpose:
  649. //-----------------------------------------------------------------------------
  650. void CTFWearable::FireGameEvent( IGameEvent *event )
  651. {
  652. const char *pszEventName = event->GetName();
  653. if ( Q_strcmp( pszEventName, "localplayer_changeteam" ) == 0 )
  654. {
  655. UpdateVisibility();
  656. }
  657. }
  658. #endif
  659. //-----------------------------------------------------------------------------
  660. // Purpose:
  661. // Choose shadow type for VM-wearables.
  662. //-----------------------------------------------------------------------------
  663. #if defined( CLIENT_DLL )
  664. ShadowType_t CTFWearableVM::ShadowCastType( void )
  665. {
  666. if ( ToTFPlayer(GetMoveParent())->ShouldDrawThisPlayer() )
  667. {
  668. // Using the viewmodel.
  669. return SHADOWS_NONE;
  670. }
  671. return SHADOWS_RENDER_TO_TEXTURE;
  672. }
  673. #endif