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.

388 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "c_weapon__stubs.h"
  8. #include "weapon_portalbasecombatweapon.h"
  9. #include "fx.h"
  10. #include "particles_localspace.h"
  11. #include "view.h"
  12. #include "particles_attractor.h"
  13. class C_WeaponPhysCannon: public CBasePortalCombatWeapon
  14. {
  15. DECLARE_CLASS( C_WeaponPhysCannon, CBasePortalCombatWeapon );
  16. public:
  17. C_WeaponPhysCannon( void );
  18. DECLARE_CLIENTCLASS();
  19. DECLARE_PREDICTABLE();
  20. virtual int DrawModel( int flags );
  21. private:
  22. bool SetupEmitter( void );
  23. bool m_bIsCurrentlyUpgrading;
  24. bool m_bWasUpgraded;
  25. CSmartPtr<CLocalSpaceEmitter> m_pLocalEmitter;
  26. CSmartPtr<CSimpleEmitter> m_pEmitter;
  27. CSmartPtr<CParticleAttractor> m_pAttractor;
  28. };
  29. STUB_WEAPON_CLASS_IMPLEMENT( weapon_physcannon, C_WeaponPhysCannon );
  30. IMPLEMENT_CLIENTCLASS_DT( C_WeaponPhysCannon, DT_WeaponPhysCannon, CWeaponPhysCannon )
  31. RecvPropBool( RECVINFO( m_bIsCurrentlyUpgrading ) ),
  32. END_RECV_TABLE()
  33. //-----------------------------------------------------------------------------
  34. // Constructor
  35. //-----------------------------------------------------------------------------
  36. C_WeaponPhysCannon::C_WeaponPhysCannon( void )
  37. {
  38. m_bWasUpgraded = false;
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. // Output : Returns true on success, false on failure.
  43. //-----------------------------------------------------------------------------
  44. bool C_WeaponPhysCannon::SetupEmitter( void )
  45. {
  46. if ( !m_pLocalEmitter.IsValid() )
  47. {
  48. m_pLocalEmitter = CLocalSpaceEmitter::Create( "physpowerup", GetRefEHandle(), LookupAttachment( "core" ) );
  49. if ( m_pLocalEmitter.IsValid() == false )
  50. return false;
  51. }
  52. if ( !m_pAttractor.IsValid() )
  53. {
  54. m_pAttractor = CParticleAttractor::Create( vec3_origin, "physpowerup_att" );
  55. if ( m_pAttractor.IsValid() == false )
  56. return false;
  57. }
  58. if ( !m_pEmitter.IsValid() )
  59. {
  60. m_pEmitter = CSimpleEmitter::Create( "physpowerup_glow" );
  61. if ( m_pEmitter.IsValid() == false )
  62. return false;
  63. }
  64. return true;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Sorts the components of a vector
  68. //-----------------------------------------------------------------------------
  69. static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx )
  70. {
  71. Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) );
  72. int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1;
  73. if (absVec[2] > absVec[maxIdx])
  74. {
  75. maxIdx = 2;
  76. }
  77. // always choose something right-handed....
  78. switch( maxIdx )
  79. {
  80. case 0:
  81. pVecIdx[0] = 1;
  82. pVecIdx[1] = 2;
  83. pVecIdx[2] = 0;
  84. break;
  85. case 1:
  86. pVecIdx[0] = 2;
  87. pVecIdx[1] = 0;
  88. pVecIdx[2] = 1;
  89. break;
  90. case 2:
  91. pVecIdx[0] = 0;
  92. pVecIdx[1] = 1;
  93. pVecIdx[2] = 2;
  94. break;
  95. }
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Compute the bounding box's center, size, and basis
  99. //-----------------------------------------------------------------------------
  100. void ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld,
  101. Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec )
  102. {
  103. // Compute the center of the hitbox in worldspace
  104. Vector vecHitboxCenter;
  105. VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter );
  106. vecHitboxCenter *= 0.5f;
  107. VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin );
  108. // Get the object's basis
  109. Vector vec[3];
  110. MatrixGetColumn( hitboxToWorld, 0, vec[0] );
  111. MatrixGetColumn( hitboxToWorld, 1, vec[1] );
  112. MatrixGetColumn( hitboxToWorld, 2, vec[2] );
  113. // vec[1] *= -1.0f;
  114. Vector vecViewDir;
  115. VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir );
  116. VectorNormalize( vecViewDir );
  117. // Project the shadow casting direction into the space of the hitbox
  118. Vector localViewDir;
  119. localViewDir[0] = DotProduct( vec[0], vecViewDir );
  120. localViewDir[1] = DotProduct( vec[1], vecViewDir );
  121. localViewDir[2] = DotProduct( vec[2], vecViewDir );
  122. // Figure out which vector has the largest component perpendicular
  123. // to the view direction...
  124. // Sort by how perpendicular it is
  125. int vecIdx[3];
  126. SortAbsVectorComponents( localViewDir, vecIdx );
  127. // Here's our hitbox basis vectors; namely the ones that are
  128. // most perpendicular to the view direction
  129. *pXVec = vec[vecIdx[0]];
  130. *pYVec = vec[vecIdx[1]];
  131. // Project them into a plane perpendicular to the view direction
  132. *pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec );
  133. *pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec );
  134. VectorNormalize( *pXVec );
  135. VectorNormalize( *pYVec );
  136. // Compute the hitbox size
  137. Vector boxSize;
  138. VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize );
  139. // We project the two longest sides into the vectors perpendicular
  140. // to the projection direction, then add in the projection of the perp direction
  141. Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] );
  142. size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) );
  143. size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) );
  144. // Add the third component into x and y
  145. size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) );
  146. size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) );
  147. // Bloat a bit, since the shadow wants to extend outside the model a bit
  148. size *= 2.0f;
  149. // Clamp the minimum size
  150. Vector2DMax( size, Vector2D(10.0f, 10.0f), size );
  151. // Factor the size into the xvec + yvec
  152. (*pXVec) *= size.x * 0.5f;
  153. (*pYVec) *= size.y * 0.5f;
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose:
  157. // Input : flags -
  158. // Output : int
  159. //-----------------------------------------------------------------------------
  160. int C_WeaponPhysCannon::DrawModel( int flags )
  161. {
  162. // If we're not ugrading, don't do anything special
  163. if ( m_bIsCurrentlyUpgrading == false && m_bWasUpgraded == false )
  164. return BaseClass::DrawModel( flags );
  165. if ( gpGlobals->frametime == 0 )
  166. return BaseClass::DrawModel( flags );
  167. if ( !m_bReadyToDraw )
  168. return 0;
  169. m_bWasUpgraded = true;
  170. // Create the particle emitter if it's not already
  171. if ( SetupEmitter() )
  172. {
  173. // Add the power-up particles
  174. // See if we should draw
  175. if ( m_bReadyToDraw == false )
  176. return 0;
  177. C_BaseAnimating *pAnimating = GetBaseAnimating();
  178. if (!pAnimating)
  179. return 0;
  180. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  181. if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
  182. return 0;
  183. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  184. if (!pStudioHdr)
  185. return false;
  186. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
  187. if ( !set )
  188. return false;
  189. int i;
  190. float fadePerc = 1.0f;
  191. if ( m_bIsCurrentlyUpgrading )
  192. {
  193. Vector vecSkew = vec3_origin;
  194. // Skew the particles in front or in back of their targets
  195. vecSkew = CurrentViewForward() * 4.0f;
  196. float spriteScale = 1.0f;
  197. spriteScale = clamp( spriteScale, 0.75f, 1.0f );
  198. SimpleParticle *sParticle;
  199. for ( i = 0; i < set->numhitboxes; ++i )
  200. {
  201. Vector vecAbsOrigin, xvec, yvec;
  202. mstudiobbox_t *pBox = set->pHitbox(i);
  203. ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec );
  204. Vector offset;
  205. Vector xDir, yDir;
  206. xDir = xvec;
  207. float xScale = VectorNormalize( xDir ) * 0.75f;
  208. yDir = yvec;
  209. float yScale = VectorNormalize( yDir ) * 0.75f;
  210. int numParticles = clamp( 4.0f * fadePerc, 1, 3 );
  211. for ( int j = 0; j < numParticles; j++ )
  212. {
  213. offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f );
  214. offset += vecSkew;
  215. sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/combinemuzzle1" ), vecAbsOrigin + offset );
  216. if ( sParticle == NULL )
  217. return 1;
  218. sParticle->m_vecVelocity = vec3_origin;
  219. sParticle->m_uchStartSize = 16.0f * spriteScale;
  220. sParticle->m_flDieTime = 0.2f;
  221. sParticle->m_flLifetime = 0.0f;
  222. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  223. sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
  224. float alpha = 40;
  225. sParticle->m_uchColor[0] = alpha;
  226. sParticle->m_uchColor[1] = alpha;
  227. sParticle->m_uchColor[2] = alpha;
  228. sParticle->m_uchStartAlpha = alpha;
  229. sParticle->m_uchEndAlpha = 0;
  230. sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
  231. }
  232. }
  233. }
  234. }
  235. int attachment = LookupAttachment( "core" );
  236. Vector coreOrigin;
  237. QAngle coreAngles;
  238. GetAttachment( attachment, coreOrigin, coreAngles );
  239. SimpleParticle *sParticle;
  240. // Do the core effects
  241. for ( int i = 0; i < 4; i++ )
  242. {
  243. sParticle = (SimpleParticle *) m_pLocalEmitter->AddParticle( sizeof(SimpleParticle), m_pLocalEmitter->GetPMaterial( "effects/strider_muzzle" ), vec3_origin );
  244. if ( sParticle == NULL )
  245. return 1;
  246. sParticle->m_vecVelocity = vec3_origin;
  247. sParticle->m_flDieTime = 0.1f;
  248. sParticle->m_flLifetime = 0.0f;
  249. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  250. sParticle->m_flRollDelta = 0.0f;
  251. float alpha = 255;
  252. sParticle->m_uchColor[0] = alpha;
  253. sParticle->m_uchColor[1] = alpha;
  254. sParticle->m_uchColor[2] = alpha;
  255. sParticle->m_uchStartAlpha = alpha;
  256. sParticle->m_uchEndAlpha = 0;
  257. if ( i < 2 )
  258. {
  259. sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
  260. sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
  261. }
  262. else
  263. {
  264. if ( random->RandomInt( 0, 20 ) == 0 )
  265. {
  266. sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
  267. sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f;
  268. sParticle->m_flDieTime = 0.25f;
  269. }
  270. else
  271. {
  272. sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
  273. sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
  274. }
  275. }
  276. }
  277. if ( m_bWasUpgraded && m_bIsCurrentlyUpgrading )
  278. {
  279. // Update our attractor point
  280. m_pAttractor->SetAttractorOrigin( coreOrigin );
  281. Vector offset;
  282. for ( int i = 0; i < 4; i++ )
  283. {
  284. offset = coreOrigin + RandomVector( -32.0f, 32.0f );
  285. sParticle = (SimpleParticle *) m_pAttractor->AddParticle( sizeof(SimpleParticle), m_pAttractor->GetPMaterial( "effects/strider_muzzle" ), offset );
  286. if ( sParticle == NULL )
  287. return 1;
  288. sParticle->m_vecVelocity = Vector(0,0,8);
  289. sParticle->m_flDieTime = 0.5f;
  290. sParticle->m_flLifetime = 0.0f;
  291. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  292. sParticle->m_flRollDelta = 0.0f;
  293. float alpha = 255;
  294. sParticle->m_uchColor[0] = alpha;
  295. sParticle->m_uchColor[1] = alpha;
  296. sParticle->m_uchColor[2] = alpha;
  297. sParticle->m_uchStartAlpha = alpha;
  298. sParticle->m_uchEndAlpha = 0;
  299. sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
  300. sParticle->m_uchEndSize = 0;
  301. }
  302. }
  303. return BaseClass::DrawModel( flags );
  304. }