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.

254 lines
8.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // TF Nail
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "tf_projectile_nail.h"
  8. #include "tf_gamerules.h"
  9. #ifdef CLIENT_DLL
  10. #include "c_basetempentity.h"
  11. #include "c_te_legacytempents.h"
  12. #include "c_te_effect_dispatch.h"
  13. #include "input.h"
  14. #include "c_tf_player.h"
  15. #include "cliententitylist.h"
  16. #endif
  17. #ifdef GAME_DLL
  18. #include "tf_player.h"
  19. #endif
  20. //=============================================================================
  21. //
  22. // TF Syringe Projectile functions (Server specific).
  23. //
  24. #define SYRINGE_MODEL "models/weapons/w_models/w_syringe_proj.mdl"
  25. #define SYRINGE_DISPATCH_EFFECT "ClientProjectile_Syringe"
  26. LINK_ENTITY_TO_CLASS( tf_projectile_syringe, CTFProjectile_Syringe );
  27. PRECACHE_REGISTER( tf_projectile_syringe );
  28. #ifdef STAGING_ONLY
  29. LINK_ENTITY_TO_CLASS( tf_projectile_tranq, CTFProjectile_Tranq );
  30. PRECACHE_REGISTER( tf_projectile_tranq );
  31. #endif // STAGING_ONLY
  32. short g_sModelIndexSyringe;
  33. void PrecacheSyringe(void *pUser)
  34. {
  35. g_sModelIndexSyringe = modelinfo->GetModelIndex( SYRINGE_MODEL );
  36. }
  37. PRECACHE_REGISTER_FN(PrecacheSyringe);
  38. //-----------------------------------------------------------------------------
  39. // CTFProjectile_Syringe
  40. //-----------------------------------------------------------------------------
  41. #define SYRINGE_GRAVITY 0.3f
  42. #define SYRINGE_VELOCITY 1000.0f
  43. // Purpose:
  44. //-----------------------------------------------------------------------------
  45. CTFBaseProjectile *CTFProjectile_Syringe::Create(
  46. const Vector &vecOrigin,
  47. const QAngle &vecAngles,
  48. CTFWeaponBaseGun *pLauncher /*= NULL*/,
  49. CBaseEntity *pOwner /*= NULL*/,
  50. CBaseEntity *pScorer /*= NULL*/,
  51. bool bCritical /*= false */
  52. ) {
  53. return CTFBaseProjectile::Create( "tf_projectile_syringe", vecOrigin, vecAngles, pOwner, SYRINGE_VELOCITY, g_sModelIndexSyringe, SYRINGE_DISPATCH_EFFECT, pScorer, bCritical );
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Purpose:
  57. //-----------------------------------------------------------------------------
  58. unsigned int CTFProjectile_Syringe::PhysicsSolidMaskForEntity( void ) const
  59. {
  60. return BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_REDTEAM | CONTENTS_BLUETEAM;
  61. }
  62. //-----------------------------------------------------------------------------
  63. float CTFProjectile_Syringe::GetGravity( void )
  64. {
  65. return SYRINGE_GRAVITY;
  66. }
  67. #ifdef STAGING_ONLY
  68. //-----------------------------------------------------------------------------
  69. // CTFProjectile_Tranq
  70. #define TRANQ_GRAVITY 0.1f
  71. #define TRANQ_VELOCITY 2000.0f
  72. #define TRANQ_STUN 0.50f
  73. #define TRANQ_DURATION 1.5f
  74. //-----------------------------------------------------------------------------
  75. // Purpose:
  76. //-----------------------------------------------------------------------------
  77. CTFBaseProjectile *CTFProjectile_Tranq::Create(
  78. const Vector &vecOrigin,
  79. const QAngle &vecAngles,
  80. CTFWeaponBaseGun *pLauncher /*= NULL*/,
  81. CBaseEntity *pOwner /*= NULL*/,
  82. CBaseEntity *pScorer /*= NULL*/,
  83. bool bCritical /*= false */
  84. ) {
  85. return CTFBaseProjectile::Create( "tf_projectile_tranq", vecOrigin, vecAngles, pOwner, TRANQ_VELOCITY, g_sModelIndexSyringe, SYRINGE_DISPATCH_EFFECT, pScorer, bCritical );
  86. }
  87. //-----------------------------------------------------------------------------
  88. float CTFProjectile_Tranq::GetGravity( void )
  89. {
  90. return TRANQ_GRAVITY;
  91. }
  92. #ifdef GAME_DLL
  93. //-----------------------------------------------------------------------------
  94. void CTFProjectile_Tranq::ProjectileTouch( CBaseEntity *pOther )
  95. {
  96. // Verify a correct "other."
  97. Assert( pOther );
  98. if ( !pOther->IsSolid() || pOther->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) )
  99. return;
  100. // Handle hitting skybox (disappear).
  101. const trace_t *pTrace = &CBaseEntity::GetTouchTrace();
  102. trace_t *pNewTrace = const_cast<trace_t*>( pTrace );
  103. if( pTrace->surface.flags & SURF_SKY )
  104. {
  105. UTIL_Remove( this );
  106. return;
  107. }
  108. // pass through ladders
  109. if( pTrace->surface.flags & CONTENTS_LADDER )
  110. return;
  111. if ( TFGameRules() && TFGameRules()->GameModeUsesUpgrades() )
  112. {
  113. // Projectile shields
  114. if ( InSameTeam( pOther ) && pOther->IsCombatItem() )
  115. return;
  116. }
  117. if ( pOther->IsWorld() )
  118. {
  119. SetAbsVelocity( vec3_origin );
  120. AddSolidFlags( FSOLID_NOT_SOLID );
  121. // Remove immediately. Clientside projectiles will stick in the wall for a bit.
  122. UTIL_Remove( this );
  123. return;
  124. }
  125. // determine the inflictor, which is the weapon which fired this projectile
  126. CBaseEntity *pInflictor = GetLauncher();
  127. CTakeDamageInfo info;
  128. info.SetAttacker( GetOwnerEntity() ); // the player who operated the thing that emitted nails
  129. info.SetInflictor( pInflictor ); // the weapon that emitted this projectile
  130. info.SetWeapon( pInflictor );
  131. info.SetDamage( GetDamage() );
  132. info.SetDamageForce( GetDamageForce() );
  133. info.SetDamagePosition( GetAbsOrigin() );
  134. info.SetDamageType( GetDamageType() );
  135. Vector dir;
  136. AngleVectors( GetAbsAngles(), &dir );
  137. pOther->DispatchTraceAttack( info, dir, pNewTrace );
  138. ApplyMultiDamage();
  139. CTFPlayer *pTFVictim = ToTFPlayer( pOther );
  140. CTFPlayer *pTFOwner = ToTFPlayer( GetOwnerEntity() );
  141. if ( pTFVictim && pTFOwner && !InSameTeam( pTFVictim ) )
  142. {
  143. // Apply Slow Condition
  144. pTFVictim->m_Shared.StunPlayer( TRANQ_DURATION, TRANQ_STUN, TF_STUN_MOVEMENT, pTFOwner );
  145. pTFVictim->m_Shared.AddCond( TF_COND_TRANQ_MARKED, PERMANENT_CONDITION, pTFOwner ); // Tranq marked until you die
  146. pTFVictim->ApplyPunchImpulseX( -2.0f ); // Apply a flinch
  147. // Apply a boost to the attacker
  148. //pTFOwner->m_Shared.AddCond( TF_COND_SPEED_BOOST, 3.0f );
  149. pTFOwner->m_Shared.AddCond( TF_COND_TRANQ_SPY_BOOST, 3.0f );
  150. }
  151. UTIL_Remove( this );
  152. }
  153. #endif // GAME_DLL
  154. #endif // STAGING_ONLY
  155. #ifdef CLIENT_DLL
  156. //-----------------------------------------------------------------------------
  157. void GetSyringeTrailParticleName( CTFPlayer *pPlayer, CAttribute_String *attrParticleName, bool bCritical )
  158. {
  159. int iTeamNumber = TF_TEAM_RED;
  160. if ( pPlayer )
  161. {
  162. iTeamNumber = pPlayer->GetTeamNumber();
  163. CTFWeaponBase *pWeapon = pPlayer->GetActiveTFWeapon();
  164. if ( pWeapon )
  165. {
  166. static CSchemaAttributeDefHandle pAttrDef_ParticleName( "projectile particle name" );
  167. CEconItemView *pItem = pWeapon->GetAttributeContainer()->GetItem();
  168. if ( pAttrDef_ParticleName && pItem )
  169. {
  170. if ( pItem->FindAttribute( pAttrDef_ParticleName, attrParticleName ) )
  171. {
  172. const char * pParticleName = attrParticleName->value().c_str();
  173. if ( iTeamNumber == TF_TEAM_BLUE && V_stristr( pParticleName, "_teamcolor_red" ))
  174. {
  175. static char pBlue[256];
  176. V_StrSubst( attrParticleName->value().c_str(), "_teamcolor_red", "_teamcolor_blue", pBlue, 256 );
  177. attrParticleName->set_value( pBlue );
  178. }
  179. return;
  180. }
  181. }
  182. }
  183. }
  184. if ( iTeamNumber == TF_TEAM_BLUE )
  185. {
  186. attrParticleName->set_value( bCritical ? "nailtrails_medic_blue_crit" : "nailtrails_medic_blue" );
  187. }
  188. else
  189. {
  190. attrParticleName->set_value( bCritical ? "nailtrails_medic_red_crit" : "nailtrails_medic_red" );
  191. }
  192. return;
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: For Synrgine Projectiles, Add effects
  196. //-----------------------------------------------------------------------------
  197. void ClientsideProjectileSyringeCallback( const CEffectData &data )
  198. {
  199. // Get the syringe and add it to the client entity list, so we can attach a particle system to it.
  200. C_TFPlayer *pPlayer = dynamic_cast<C_TFPlayer*>( ClientEntityList().GetBaseEntityFromHandle( data.m_hEntity ) );
  201. if ( pPlayer )
  202. {
  203. C_LocalTempEntity *pSyringe = ClientsideProjectileCallback( data, SYRINGE_GRAVITY );
  204. if ( pSyringe )
  205. {
  206. CAttribute_String attrParticleName;
  207. pSyringe->m_nSkin = ( pPlayer->GetTeamNumber() == TF_TEAM_RED ) ? 0 : 1;
  208. bool bCritical = ( ( data.m_nDamageType & DMG_CRITICAL ) != 0 );
  209. GetSyringeTrailParticleName( pPlayer, &attrParticleName, bCritical );
  210. pSyringe->AddParticleEffect( attrParticleName.value().c_str() );
  211. pSyringe->AddEffects( EF_NOSHADOW );
  212. pSyringe->flags |= FTENT_USEFASTCOLLISIONS;
  213. }
  214. }
  215. }
  216. DECLARE_CLIENT_EFFECT( SYRINGE_DISPATCH_EFFECT, ClientsideProjectileSyringeCallback );
  217. #endif