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.

860 lines
23 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "econ_wearable.h"
  8. #include "vcollide_parse.h"
  9. #ifdef CLIENT_DLL
  10. #include "functionproxy.h"
  11. #include "c_te_effect_dispatch.h"
  12. #endif // CLIENT_DLL
  13. #ifdef TF_CLIENT_DLL
  14. #include "c_team.h"
  15. #include "tf_shareddefs.h"
  16. #include "tf_weapon_jar.h"
  17. #include "c_tf_player.h"
  18. #endif // TF_CLIENT_DLL
  19. #ifdef TF_DLL
  20. #include "tf_player.h"
  21. #endif // TF_DLL
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include "tier0/memdbgon.h"
  24. LINK_ENTITY_TO_CLASS( wearable_item, CEconWearable );
  25. IMPLEMENT_NETWORKCLASS_ALIASED( EconWearable, DT_WearableItem )
  26. // Network Table --
  27. BEGIN_NETWORK_TABLE( CEconWearable, DT_WearableItem )
  28. END_NETWORK_TABLE()
  29. // -- Network Table
  30. // Data Desc --
  31. BEGIN_DATADESC( CEconWearable )
  32. END_DATADESC()
  33. // -- Data Desc
  34. PRECACHE_REGISTER( wearable_item );
  35. IMPLEMENT_NETWORKCLASS_ALIASED( TFWearableItem, DT_TFWearableItem )
  36. // Network Table --
  37. BEGIN_NETWORK_TABLE( CTFWearableItem, DT_TFWearableItem )
  38. END_NETWORK_TABLE()
  39. // -- Network Table
  40. // Data Desc --
  41. BEGIN_DATADESC( CTFWearableItem )
  42. END_DATADESC()
  43. // -- Data Desc
  44. //-----------------------------------------------------------------------------
  45. // SHARED CODE
  46. //-----------------------------------------------------------------------------
  47. CEconWearable::CEconWearable()
  48. {
  49. m_bAlwaysAllow = false;
  50. };
  51. void CEconWearable::InternalSetPlayerDisplayModel( void )
  52. {
  53. int iClass = 0;
  54. int iTeam = 0;
  55. #if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  56. CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
  57. if ( pTFPlayer )
  58. {
  59. iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
  60. iTeam = pTFPlayer->GetTeamNumber();
  61. }
  62. #endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  63. // Set our model to the player model
  64. CEconItemView *pItem = GetAttributeContainer()->GetItem();
  65. if ( pItem && pItem->IsValid() )
  66. {
  67. const char *pszPlayerDisplayModel = pItem->GetPlayerDisplayModel( iClass, iTeam );
  68. if ( pszPlayerDisplayModel )
  69. {
  70. if ( pItem->GetStaticData()->IsContentStreamable() )
  71. {
  72. modelinfo->RegisterDynamicModel( pszPlayerDisplayModel, IsClient() );
  73. if ( pItem->GetVisionFilteredDisplayModel() && pItem->GetVisionFilteredDisplayModel()[ 0 ] != '\0' )
  74. {
  75. modelinfo->RegisterDynamicModel( pItem->GetVisionFilteredDisplayModel(), IsClient() );
  76. }
  77. }
  78. SetModel( pszPlayerDisplayModel );
  79. }
  80. }
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Set up the item. GC data may not be available here depending on
  84. // where we're called from.
  85. //-----------------------------------------------------------------------------
  86. void CEconWearable::Spawn( void )
  87. {
  88. InitializeAttributes();
  89. Precache();
  90. InternalSetPlayerDisplayModel();
  91. BaseClass::Spawn();
  92. AddEffects( EF_BONEMERGE );
  93. AddEffects( EF_BONEMERGE_FASTCULL );
  94. #if !defined( CLIENT_DLL )
  95. SetCollisionGroup( COLLISION_GROUP_WEAPON );
  96. SetBlocksLOS( false );
  97. #endif
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose: Player touches the item. Currently wearables don't appear in the
  101. // world, so this is only called directly during equipment assignment.
  102. //-----------------------------------------------------------------------------
  103. void CEconWearable::GiveTo( CBaseEntity *pOther )
  104. {
  105. CBasePlayer *pPlayer = ToBasePlayer(pOther);
  106. if ( !pPlayer )
  107. return;
  108. #if !defined( CLIENT_DLL )
  109. pPlayer->EquipWearable( this );
  110. #endif
  111. }
  112. //-----------------------------------------------------------------------------
  113. // Purpose:
  114. //-----------------------------------------------------------------------------
  115. void CEconWearable::RemoveFrom( CBaseEntity *pOther )
  116. {
  117. CBasePlayer *pPlayer = ToBasePlayer(pOther);
  118. if ( !pPlayer )
  119. return;
  120. #if !defined( CLIENT_DLL )
  121. pPlayer->RemoveWearable( this );
  122. #endif
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose:
  126. //-----------------------------------------------------------------------------
  127. int CEconWearable::GetSkin( void )
  128. {
  129. CEconItemView *pItem = GetAttributeContainer()->GetItem(); // Safe. Checked in base class call.
  130. if ( pItem )
  131. {
  132. int iSkin = pItem->GetSkin( GetTeamNumber() );
  133. if ( iSkin > -1 )
  134. {
  135. return iSkin;
  136. }
  137. }
  138. return ( GetTeamNumber() == (LAST_SHARED_TEAM+1) ) ? 0 : 1;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: Attaches the item to the player.
  142. //-----------------------------------------------------------------------------
  143. void CEconWearable::Equip( CBasePlayer* pOwner )
  144. {
  145. if ( !CanEquip( pOwner ) )
  146. {
  147. RemoveFrom( pOwner );
  148. return;
  149. }
  150. SetTouch( NULL );
  151. SetAbsVelocity( vec3_origin );
  152. CBaseEntity *pFollowEntity = pOwner;
  153. if ( IsViewModelWearable() )
  154. {
  155. pFollowEntity = pOwner->GetViewModel();
  156. }
  157. FollowEntity( pFollowEntity, true );
  158. SetOwnerEntity( pOwner );
  159. ReapplyProvision();
  160. ChangeTeam( pOwner->GetTeamNumber() );
  161. m_nSkin = GetSkin();
  162. #ifdef GAME_DLL
  163. UpdateModelToClass();
  164. UpdateBodygroups( pOwner, true );
  165. PlayAnimForPlaybackEvent( WAP_ON_SPAWN );
  166. #endif
  167. }
  168. //-----------------------------------------------------------------------------
  169. // Purpose: Remove item from the player.
  170. //-----------------------------------------------------------------------------
  171. void CEconWearable::UnEquip( CBasePlayer* pOwner )
  172. {
  173. #ifdef CLIENT_DLL
  174. SetParticleSystemsVisible( PARTICLE_SYSTEM_STATE_NOT_VISIBLE );
  175. #endif
  176. #ifdef GAME_DLL
  177. UpdateBodygroups( pOwner, false );
  178. #endif
  179. StopFollowingEntity();
  180. SetOwnerEntity( NULL );
  181. ReapplyProvision();
  182. }
  183. /*
  184. //-----------------------------------------------------------------------------
  185. // Purpose: Hides or shows masked bodygroups associated with this item.
  186. //-----------------------------------------------------------------------------
  187. bool CEconWearable::UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState )
  188. {
  189. if ( !pOwner )
  190. return false;
  191. CAttributeContainer *pCont = GetAttributeContainer();
  192. if ( !pCont )
  193. return false;
  194. CEconItemView *pItem = pCont->GetItem();
  195. if ( !pItem )
  196. return false;
  197. int iTeam = pOwner->GetTeamNumber();
  198. int iNumBodyGroups = pItem->GetNumModifiedBodyGroups( iTeam );
  199. for ( int i=0; i<iNumBodyGroups; ++i )
  200. {
  201. int iBody = 0;
  202. const char *pszBodyGroup = pItem->GetModifiedBodyGroup( iTeam, i, iBody );
  203. int iBodyGroup = pOwner->FindBodygroupByName( pszBodyGroup );
  204. if ( iBodyGroup == -1 )
  205. continue;
  206. pOwner->SetBodygroup( iBodyGroup, iState );
  207. }
  208. return true;
  209. }
  210. */
  211. //-----------------------------------------------------------------------------
  212. // Purpose:
  213. //-----------------------------------------------------------------------------
  214. void CEconWearable::OnWearerDeath( void )
  215. {
  216. #ifdef CLIENT_DLL
  217. UpdateParticleSystems();
  218. #endif
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Purpose:
  222. //-----------------------------------------------------------------------------
  223. int CEconWearable::GetDropType()
  224. {
  225. CAttributeContainer *pCont = GetAttributeContainer();
  226. if ( !pCont )
  227. return 0;
  228. CEconItemView *pItem = pCont->GetItem();
  229. if ( pItem )
  230. return pItem->GetDropType();
  231. else
  232. return 0;
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Purpose: Ensures that a player's correct body groups are enabled on client respawn.
  236. //-----------------------------------------------------------------------------
  237. void CEconWearable::UpdateWearableBodyGroups( CBasePlayer* pPlayer )
  238. {
  239. if ( !pPlayer )
  240. return;
  241. for ( int i=0; i<pPlayer->GetNumWearables(); ++i )
  242. {
  243. CEconWearable* pItem = pPlayer->GetWearable(i);
  244. if ( !pItem )
  245. continue;
  246. // Dynamic models which are not yet rendering do not modify bodygroups
  247. if ( pItem->IsDynamicModelLoading() )
  248. continue;
  249. // On the client, ignore items that aren't valid.
  250. #ifdef TF_CLIENT_DLL
  251. if ( pItem->EntityDeemedInvalid() )
  252. continue;
  253. #endif
  254. int nVisibleState = 1;
  255. #ifdef TF_CLIENT_DLL
  256. if ( pItem->ShouldHideForVisionFilterFlags() )
  257. {
  258. // Items that shouldn't draw (pyro-vision filtered) shouldn't change any body group states
  259. // unless they have no model (hatless hats)
  260. nVisibleState = 0;
  261. }
  262. #endif
  263. pItem->UpdateBodygroups( pPlayer, nVisibleState );
  264. }
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Purpose:
  268. //-----------------------------------------------------------------------------
  269. CTFWearableItem::CTFWearableItem()
  270. {
  271. }
  272. //-----------------------------------------------------------------------------
  273. // SERVER ONLY CODE
  274. //-----------------------------------------------------------------------------
  275. #if defined( GAME_DLL )
  276. #endif
  277. //-----------------------------------------------------------------------------
  278. // CLIENT ONLY CODE
  279. //-----------------------------------------------------------------------------
  280. #if defined( CLIENT_DLL )
  281. //-----------------------------------------------------------------------------
  282. // Purpose: Mirror should draw logic.
  283. //-----------------------------------------------------------------------------
  284. ShadowType_t CEconWearable::ShadowCastType()
  285. {
  286. if ( ShouldDraw() )
  287. {
  288. return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
  289. }
  290. return SHADOWS_NONE;
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Purpose:
  294. //-----------------------------------------------------------------------------
  295. bool CEconWearable::ShouldDraw( void )
  296. {
  297. CBasePlayer *pPlayerOwner = ToBasePlayer( GetOwnerEntity() );
  298. if ( !pPlayerOwner )
  299. {
  300. return false;
  301. }
  302. bool bUseViewModel = !pPlayerOwner->ShouldDrawThisPlayer();
  303. // Don't show view models if we're drawing the real player, and don't show non view models if using view models.
  304. if ( bUseViewModel )
  305. {
  306. // VM mode.
  307. if ( !IsViewModelWearable() )
  308. {
  309. return false;
  310. }
  311. }
  312. else
  313. {
  314. // Non-viewmodel mode.
  315. if ( IsViewModelWearable() )
  316. {
  317. return false;
  318. }
  319. }
  320. if ( !ShouldDrawWhenPlayerIsDead() && !pPlayerOwner->IsAlive() )
  321. {
  322. return false;
  323. }
  324. if ( pPlayerOwner->GetTeamNumber() == TEAM_SPECTATOR )
  325. {
  326. return false;
  327. }
  328. return BaseClass::ShouldDraw();
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Purpose:
  332. //-----------------------------------------------------------------------------
  333. void CEconWearable::OnDataChanged( DataUpdateType_t updateType )
  334. {
  335. BaseClass::OnDataChanged( updateType );
  336. if ( updateType == DATA_UPDATE_CREATED )
  337. {
  338. SetNextClientThink( CLIENT_THINK_ALWAYS );
  339. }
  340. // Update our visibility in case our parents' has changed.
  341. UpdateVisibility();
  342. UpdateParticleSystems();
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose:
  346. //-----------------------------------------------------------------------------
  347. void CEconWearable::ClientThink( void )
  348. {
  349. BaseClass::ClientThink();
  350. UpdateParticleSystems();
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Purpose:
  354. //-----------------------------------------------------------------------------
  355. bool CEconWearable::ShouldDrawParticleSystems( void )
  356. {
  357. // Make sure the entity we're attaching to is being drawn
  358. CBasePlayer *pPlayerOwner = ToBasePlayer( GetOwnerEntity() );
  359. if ( !pPlayerOwner )
  360. {
  361. Assert ( "CEconWearable has no owner?" ); // Not sure what this means - is is visible or not?
  362. return false;
  363. }
  364. if ( pPlayerOwner->ShouldDrawThisPlayer() )
  365. {
  366. return true;
  367. }
  368. return false;
  369. }
  370. RenderGroup_t CEconWearable::GetRenderGroup()
  371. {
  372. if ( IsViewModelWearable() )
  373. return RENDER_GROUP_VIEW_MODEL_TRANSLUCENT;
  374. return BaseClass::GetRenderGroup();
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose: Wearable tint colors
  378. //-----------------------------------------------------------------------------
  379. class CProxyItemTintColor : public CResultProxy
  380. {
  381. public:
  382. void OnBind( void *pC_BaseEntity )
  383. {
  384. Assert( m_pResult );
  385. Vector vResult = Vector( 0, 0, 0 );
  386. if ( pC_BaseEntity )
  387. {
  388. CEconItemView *pScriptItem = NULL;
  389. IClientRenderable *pRend = (IClientRenderable *)pC_BaseEntity;
  390. C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
  391. if ( pEntity )
  392. {
  393. CEconEntity *pItem = dynamic_cast< CEconEntity* >( pEntity );
  394. if ( pItem )
  395. {
  396. pScriptItem = pItem->GetAttributeContainer()->GetItem();
  397. }
  398. else if ( pEntity->GetOwnerEntity() )
  399. {
  400. // Try the owner (for viewmodels, etc).
  401. pEntity = pEntity->GetOwnerEntity();
  402. pItem = dynamic_cast< CEconEntity* >( pEntity );
  403. if ( pItem )
  404. {
  405. pScriptItem = pItem->GetAttributeContainer()->GetItem();
  406. }
  407. }
  408. }
  409. else
  410. {
  411. // Proxy data can be a script created item itself, if we're in a vgui CModelPanel
  412. pScriptItem = dynamic_cast< CEconItemView* >( pRend );
  413. }
  414. #ifdef TF_CLIENT_DLL
  415. if ( !pScriptItem )
  416. {
  417. // Might be a throwable
  418. CTFWeaponBaseGrenadeProj *pProjectile = dynamic_cast< CTFWeaponBaseGrenadeProj* >( pEntity );
  419. if ( pProjectile )
  420. {
  421. CEconEntity *pItem = dynamic_cast< CEconEntity* >( pProjectile->GetLauncher() );
  422. if ( pItem )
  423. {
  424. pScriptItem = pItem->GetAttributeContainer()->GetItem();
  425. }
  426. }
  427. }
  428. if ( pScriptItem && pScriptItem->IsValid() )
  429. {
  430. const bool bAltColor = pEntity && pEntity->GetTeam() > 0
  431. ? pEntity->GetTeam()->GetTeamNumber() == TF_TEAM_BLUE
  432. : pScriptItem->GetFlags() & kEconItemFlagClient_ForceBlueTeam
  433. ? true
  434. : false;
  435. int iModifiedRGB = pScriptItem->GetModifiedRGBValue( bAltColor );
  436. if ( iModifiedRGB )
  437. {
  438. // The attrib returns a packed RGB with values between 0 & 255 packed into the bottom 3 bytes.
  439. Color clr = Color( ((iModifiedRGB & 0xFF0000) >> 16), ((iModifiedRGB & 0xFF00) >> 8), (iModifiedRGB & 0xFF) );
  440. vResult.x = clamp( clr.r() * (1.f / 255.0f), 0.f, 1.0f );
  441. vResult.y = clamp( clr.g() * (1.f / 255.0f), 0.f, 1.0f );
  442. vResult.z = clamp( clr.b() * (1.f / 255.0f), 0.f, 1.0f );
  443. }
  444. }
  445. #endif // TF_CLIENT_DLL
  446. }
  447. m_pResult->SetVecValue( vResult.x, vResult.y, vResult.z );
  448. }
  449. };
  450. EXPOSE_INTERFACE( CProxyItemTintColor, IMaterialProxy, "ItemTintColor" IMATERIAL_PROXY_INTERFACE_VERSION );
  451. //============================================================================================================================
  452. extern ConVar r_propsmaxdist;
  453. //-----------------------------------------------------------------------------
  454. // Purpose:
  455. //-----------------------------------------------------------------------------
  456. C_EconWearableGib::C_EconWearableGib()
  457. {
  458. m_fDeathTime = -1;
  459. m_iHealth = 0;
  460. m_bParented = false;
  461. m_bDelayedInit = false;
  462. }
  463. C_EconWearableGib::~C_EconWearableGib()
  464. {
  465. PhysCleanupFrictionSounds( this );
  466. VPhysicsDestroyObject();
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Purpose:
  470. //-----------------------------------------------------------------------------
  471. bool C_EconWearableGib::Initialize( bool bWillBeParented )
  472. {
  473. m_bParented = bWillBeParented;
  474. return InitializeAsClientEntity( STRING( GetModelName() ), RENDER_GROUP_OPAQUE_ENTITY );
  475. }
  476. //-----------------------------------------------------------------------------
  477. // Purpose:
  478. //-----------------------------------------------------------------------------
  479. CStudioHdr* C_EconWearableGib::OnNewModel()
  480. {
  481. CStudioHdr* pCStudioHdr = BaseClass::OnNewModel();
  482. if ( m_bDelayedInit && !IsDynamicModelLoading() )
  483. {
  484. FinishModelInitialization();
  485. }
  486. return pCStudioHdr;
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Purpose:
  490. //-----------------------------------------------------------------------------
  491. void C_EconWearableGib::SpawnClientEntity( void )
  492. {
  493. if ( !IsDynamicModelLoading() )
  494. {
  495. FinishModelInitialization();
  496. }
  497. else
  498. {
  499. m_bDelayedInit = true;
  500. }
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Purpose:
  504. //-----------------------------------------------------------------------------
  505. bool C_EconWearableGib::FinishModelInitialization( void )
  506. {
  507. UpdateThinkState();
  508. const model_t *mod = GetModel();
  509. if ( mod )
  510. {
  511. Vector mins, maxs;
  512. modelinfo->GetModelBounds( mod, mins, maxs );
  513. SetCollisionBounds( mins, maxs );
  514. }
  515. if ( !m_bParented )
  516. {
  517. // Create the object in the physics system
  518. solid_t tmpSolid;
  519. if ( !PhysModelParseSolid( tmpSolid, this, GetModelIndex() ) )
  520. {
  521. DevMsg("C_EconWearableGib::FinishModelInitialization: PhysModelParseSolid failed for entity %i.\n", GetModelIndex() );
  522. return false;
  523. }
  524. else
  525. {
  526. m_pPhysicsObject = VPhysicsInitNormal( SOLID_VPHYSICS, 0, false, &tmpSolid );
  527. if ( !m_pPhysicsObject )
  528. {
  529. // failed to create a physics object
  530. DevMsg(" C_EconWearableGib::FinishModelInitialization: VPhysicsInitNormal() failed for %s.\n", STRING(GetModelName()) );
  531. return false;
  532. }
  533. }
  534. }
  535. Spawn();
  536. if ( m_fadeMinDist < 0 )
  537. {
  538. // start fading out at 75% of r_propsmaxdist
  539. m_fadeMaxDist = r_propsmaxdist.GetFloat();
  540. m_fadeMinDist = r_propsmaxdist.GetFloat() * 0.75f;
  541. }
  542. SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  543. UpdatePartitionListEntry();
  544. CollisionProp()->UpdatePartition();
  545. SetBlocksLOS( false ); // this should be a small object
  546. // Set up shadows; do it here so that objects can change shadowcasting state
  547. CreateShadow();
  548. UpdateVisibility();
  549. return true;
  550. }
  551. //-----------------------------------------------------------------------------
  552. // Purpose:
  553. //-----------------------------------------------------------------------------
  554. void C_EconWearableGib::Spawn()
  555. {
  556. BaseClass::Spawn();
  557. m_takedamage = DAMAGE_EVENTS_ONLY;
  558. }
  559. //-----------------------------------------------------------------------------
  560. // Purpose:
  561. //-----------------------------------------------------------------------------
  562. bool C_EconWearableGib::ValidateEntityAttachedToPlayer( bool &bShouldRetry )
  563. {
  564. bShouldRetry = false;
  565. // Always valid as long as we're not parented to anything
  566. return (GetMoveParent() == NULL);
  567. }
  568. #define WEARABLE_FADEOUT_TIME 1.0f
  569. //-----------------------------------------------------------------------------
  570. // Purpose: Figure out if we need to think or not
  571. //-----------------------------------------------------------------------------
  572. bool C_EconWearableGib::UpdateThinkState( void )
  573. {
  574. if ( m_fDeathTime > 0 )
  575. {
  576. // If we're in the active fadeout portion, think rapidly. Otherwise, wait for that time.
  577. if ( (m_fDeathTime - gpGlobals->curtime) > WEARABLE_FADEOUT_TIME )
  578. {
  579. SetNextClientThink( m_fDeathTime - WEARABLE_FADEOUT_TIME );
  580. }
  581. else
  582. {
  583. SetNextClientThink( CLIENT_THINK_ALWAYS );
  584. }
  585. return true;
  586. }
  587. SetNextClientThink( CLIENT_THINK_NEVER );
  588. return false;
  589. }
  590. //-----------------------------------------------------------------------------
  591. // Purpose:
  592. //-----------------------------------------------------------------------------
  593. void C_EconWearableGib::ClientThink( void )
  594. {
  595. if ( (m_fDeathTime > 0) && ((m_fDeathTime - gpGlobals->curtime) <= WEARABLE_FADEOUT_TIME) )
  596. {
  597. if ( m_fDeathTime <= gpGlobals->curtime )
  598. {
  599. Release(); // Die
  600. return;
  601. }
  602. // fade out
  603. float alpha = (m_fDeathTime - gpGlobals->curtime) / WEARABLE_FADEOUT_TIME;
  604. SetRenderMode( kRenderTransTexture );
  605. SetRenderColorA( alpha * 256 );
  606. }
  607. UpdateThinkState();
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Purpose:
  611. //-----------------------------------------------------------------------------
  612. void C_EconWearableGib::StartFadeOut( float fDelay )
  613. {
  614. m_fDeathTime = gpGlobals->curtime + fDelay + WEARABLE_FADEOUT_TIME;
  615. UpdateThinkState();
  616. }
  617. //-----------------------------------------------------------------------------
  618. // Purpose:
  619. //-----------------------------------------------------------------------------
  620. void C_EconWearableGib::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName )
  621. {
  622. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  623. if( !pPhysicsObject )
  624. return;
  625. Vector dir = pTrace->endpos - pTrace->startpos;
  626. int iDamage = 0;
  627. if ( iDamageType & DMG_BLAST )
  628. {
  629. iDamage = VectorLength( dir );
  630. dir *= 500; // adjust impact strenght
  631. // apply force at object mass center
  632. pPhysicsObject->ApplyForceCenter( dir );
  633. }
  634. else
  635. {
  636. Vector hitpos;
  637. VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
  638. VectorNormalize( dir );
  639. // guess avg damage
  640. if ( iDamageType == DMG_BULLET )
  641. {
  642. iDamage = 30;
  643. }
  644. else
  645. {
  646. iDamage = 50;
  647. }
  648. dir *= 4000; // adjust impact strenght
  649. // apply force where we hit it
  650. pPhysicsObject->ApplyForceOffset( dir, hitpos );
  651. }
  652. }
  653. #if 0
  654. #ifdef _DEBUG
  655. #include "econ_item_system.h"
  656. static CUtlVector< const char * > s_possibleModels;
  657. static CUtlVector< const GameItemDefinition_t * > s_possibleDefinitions;
  658. void Dbg_TestDynamicWearableGibs( void )
  659. {
  660. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  661. if ( !pLocalPlayer )
  662. return;
  663. C_EconWearableGib *pEntity = new C_EconWearableGib();
  664. if ( !pEntity )
  665. return;
  666. Vector forward;
  667. pLocalPlayer->EyeVectors( &forward );
  668. trace_t tr;
  669. UTIL_TraceLine( pLocalPlayer->EyePosition(), pLocalPlayer->EyePosition() + (forward * 256), MASK_NPCSOLID, pLocalPlayer, COLLISION_GROUP_NONE, &tr );
  670. Vector position = tr.endpos;
  671. if ( s_possibleModels.Count() == 0 )
  672. {
  673. FOR_EACH_MAP( ItemSystem()->GetItemSchema()->GetItemDefinitionMap(), nDefn )
  674. {
  675. const GameItemDefinition_t *pDefn = dynamic_cast<GameItemDefinition_t *>( ItemSystem()->GetItemSchema()->GetItemDefinitionMap()[nDefn] );
  676. if ( !pDefn )
  677. continue;
  678. const char *pszModel = pDefn->GetPlayerDisplayModel( 0 );
  679. if ( pszModel && pszModel[0] && pszModel[0] != '?' && pDefn->BLoadOnDemand() && pDefn->GetDropType() == ITEM_DROP_TYPE_DROP )
  680. {
  681. s_possibleModels.AddToTail( pszModel );
  682. s_possibleDefinitions.AddToTail( pDefn );
  683. }
  684. }
  685. }
  686. Assert( s_possibleModels.Count() );
  687. int spawnIndex = random->RandomInt( 0, s_possibleModels.Count() - 1 );
  688. const char *pszModelName = s_possibleModels[ spawnIndex ];
  689. const GameItemDefinition_t *pDefn = s_possibleDefinitions[ spawnIndex ];
  690. Msg( "Spawning: %s\n", pszModelName );
  691. pEntity->SetModelName( AllocPooledString( pszModelName ) );
  692. pEntity->SetAbsOrigin( position );
  693. pEntity->SetAbsAngles( vec3_angle );
  694. pEntity->SetOwnerEntity( pLocalPlayer );
  695. pEntity->ChangeTeam( pLocalPlayer->GetTeamNumber() ); // our gibs will match our team; this will probably not be used for anything besides team coloring
  696. // Copy the script created item data over
  697. pEntity->GetAttributeContainer()->GetItem()->Init( pDefn->GetDefinitionIndex(), pDefn->GetQuality(), pDefn->GetMinLevel(), true );
  698. if ( !pEntity->Initialize( false ) )
  699. {
  700. pEntity->Release();
  701. return;
  702. }
  703. pEntity->StartFadeOut( 15.0f );
  704. return;
  705. IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
  706. if ( !pPhysicsObject )
  707. {
  708. pEntity->Release();
  709. return;
  710. }
  711. // randomize velocity by 5%
  712. Vector rndVel = Vector(0,0,100);
  713. pPhysicsObject->AddVelocity( &rndVel, &vec3_origin );
  714. }
  715. static ConCommand dbg_testdynamicwearablegib( "dbg_testdynamicwearablegib", Dbg_TestDynamicWearableGibs, "", FCVAR_CHEAT );
  716. #endif // _DEBUG
  717. #endif
  718. #endif // client only