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.

476 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "c_basehelicopter.h"
  8. #include "fx_impact.h"
  9. #include "IEffects.h"
  10. #include "simple_keys.h"
  11. #include "fx_envelope.h"
  12. #include "fx_line.h"
  13. #include "iefx.h"
  14. #include "dlight.h"
  15. #include "c_sprite.h"
  16. #include "clienteffectprecachesystem.h"
  17. #include <bitbuf.h>
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. #define GUNSHIP_MSG_BIG_SHOT 1
  21. #define GUNSHIP_MSG_STREAKS 2
  22. #define GUNSHIP_MSG_DEAD 3
  23. #define GUNSHIPFX_BIG_SHOT_TIME 3.0f
  24. CLIENTEFFECT_REGISTER_BEGIN( PrecacheGunshipFX )
  25. CLIENTEFFECT_MATERIAL( "sprites/bluelaser1" )
  26. CLIENTEFFECT_REGISTER_END()
  27. //-----------------------------------------------------------------------------
  28. // Big belly shot FX
  29. //-----------------------------------------------------------------------------
  30. class C_GunshipFX : public C_EnvelopeFX
  31. {
  32. public:
  33. typedef C_EnvelopeFX BaseClass;
  34. C_GunshipFX();
  35. void Update( C_BaseEntity *pOwner, const Vector &targetPos );
  36. // Returns the bounds relative to the origin (render bounds)
  37. virtual void GetRenderBounds( Vector& mins, Vector& maxs )
  38. {
  39. ClearBounds( mins, maxs );
  40. AddPointToBounds( m_worldPosition, mins, maxs );
  41. AddPointToBounds( m_targetPosition, mins, maxs );
  42. mins -= GetRenderOrigin();
  43. maxs -= GetRenderOrigin();
  44. }
  45. virtual int DrawModel( int flags );
  46. C_BaseEntity *m_pOwner;
  47. Vector m_targetPosition;
  48. Vector m_beamEndPosition;
  49. };
  50. //-----------------------------------------------------------------------------
  51. // Purpose:
  52. //-----------------------------------------------------------------------------
  53. C_GunshipFX::C_GunshipFX( void )
  54. {
  55. m_pOwner = NULL;
  56. }
  57. enum
  58. {
  59. GUNSHIPFX_WARP_SCALE = 0,
  60. GUNSHIPFX_DARKNESS,
  61. GUNSHIPFX_FLARE_COLOR,
  62. GUNSHIPFX_FLARE_SIZE,
  63. GUNSHIPFX_NARROW_BEAM_COLOR,
  64. GUNSHIPFX_NARROW_BEAM_SIZE,
  65. GUNSHIPFX_WIDE_BEAM_COLOR,
  66. GUNSHIPFX_WIDE_BEAM_SIZE,
  67. GUNSHIPFX_AFTERGLOW_COLOR,
  68. GUNSHIPFX_WIDE_BEAM_LENGTH,
  69. // must be last
  70. GUNSHIPFX_PARAMETERS,
  71. };
  72. class CGunshipFXEnvelope
  73. {
  74. public:
  75. CGunshipFXEnvelope();
  76. void AddKey( int parameterIndex, const CSimpleKeyInterp &key )
  77. {
  78. Assert( parameterIndex >= 0 && parameterIndex < GUNSHIPFX_PARAMETERS );
  79. if ( parameterIndex >= 0 && parameterIndex < GUNSHIPFX_PARAMETERS )
  80. {
  81. m_parameters[parameterIndex].Insert( key );
  82. }
  83. }
  84. CSimpleKeyList m_parameters[GUNSHIPFX_PARAMETERS];
  85. };
  86. // NOTE: Beam widths are half-widths or radii, so this is a beam that represents a cylinder with 2" radius
  87. const float NARROW_BEAM_WIDTH = 32;
  88. const float WIDE_BEAM_WIDTH = 2;
  89. const float FLARE_SIZE = 128;
  90. const float DARK_SIZE = 16;
  91. const float AFTERGLOW_SIZE = 64;
  92. CGunshipFXEnvelope::CGunshipFXEnvelope()
  93. {
  94. // Glow flare
  95. AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) );
  96. AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 0.5, KEY_SPLINE, 1 ) );
  97. AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 2.9, KEY_LINEAR, 1 ) );
  98. AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 3.2, KEY_DECELERATE, 0 ) );
  99. AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) );
  100. AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 2.9, KEY_ACCELERATE, 1 ) );
  101. AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 5.0, KEY_LINEAR, 1 ) );
  102. // Ground beam
  103. AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0.0 ) );
  104. AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 2.5, KEY_SPLINE, 1.0 ) );
  105. AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) );
  106. AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 3.2, KEY_ACCELERATE, 0 ) );
  107. AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) );
  108. AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 2.5, KEY_SPLINE, 0.25 ) );
  109. AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 2.8, KEY_ACCELERATE, 1 ) );
  110. AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 3.0, KEY_ACCELERATE, 4 ) );
  111. AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 3.2, KEY_DECELERATE, 0 ) );
  112. // Glow color on the ship
  113. AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) );
  114. AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) );
  115. AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 5.0, KEY_SPLINE, 0 ) );
  116. }
  117. CGunshipFXEnvelope g_GunshipCannonEnvelope;
  118. static void ScaleColor( color32 &out, const color32 &in, float scale )
  119. {
  120. out.r = (byte)(int)((float)in.r * scale);
  121. out.g = (byte)(int)((float)in.g * scale);
  122. out.b = (byte)(int)((float)in.b * scale);
  123. out.a = (byte)(int)((float)in.a * scale);
  124. }
  125. static void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color )
  126. {
  127. unsigned char pColor[4] = { color.r, color.g, color.b, color.a };
  128. // Generate half-widths
  129. flWidth *= 0.5f;
  130. flHeight *= 0.5f;
  131. // Compute direction vectors for the sprite
  132. Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 );
  133. VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd );
  134. float flDist = VectorNormalize( fwd );
  135. if (flDist >= 1e-3)
  136. {
  137. CrossProduct( CurrentViewUp(), fwd, right );
  138. flDist = VectorNormalize( right );
  139. if (flDist >= 1e-3)
  140. {
  141. CrossProduct( fwd, right, up );
  142. }
  143. else
  144. {
  145. // In this case, fwd == g_vecVUp, it's right above or
  146. // below us in screen space
  147. CrossProduct( fwd, CurrentViewRight(), up );
  148. VectorNormalize( up );
  149. CrossProduct( up, fwd, right );
  150. }
  151. }
  152. Vector left = -right;
  153. Vector down = -up;
  154. Vector back = -fwd;
  155. CMatRenderContextPtr pRenderContext( materials );
  156. CMeshBuilder meshBuilder;
  157. Vector point;
  158. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  159. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  160. meshBuilder.Color4ubv (pColor);
  161. meshBuilder.TexCoord2f (0, 0, 1);
  162. VectorMA (vecOrigin, -flHeight, up, point);
  163. VectorMA (point, -flWidth, right, point);
  164. meshBuilder.TangentS3fv( left.Base() );
  165. meshBuilder.TangentT3fv( down.Base() );
  166. meshBuilder.Normal3fv( back.Base() );
  167. meshBuilder.Position3fv (point.Base());
  168. meshBuilder.AdvanceVertex();
  169. meshBuilder.Color4ubv (pColor);
  170. meshBuilder.TexCoord2f (0, 0, 0);
  171. VectorMA (vecOrigin, flHeight, up, point);
  172. VectorMA (point, -flWidth, right, point);
  173. meshBuilder.TangentS3fv( left.Base() );
  174. meshBuilder.TangentT3fv( down.Base() );
  175. meshBuilder.Normal3fv( back.Base() );
  176. meshBuilder.Position3fv (point.Base());
  177. meshBuilder.AdvanceVertex();
  178. meshBuilder.Color4ubv (pColor);
  179. meshBuilder.TexCoord2f (0, 1, 0);
  180. VectorMA (vecOrigin, flHeight, up, point);
  181. VectorMA (point, flWidth, right, point);
  182. meshBuilder.TangentS3fv( left.Base() );
  183. meshBuilder.TangentT3fv( down.Base() );
  184. meshBuilder.Normal3fv( back.Base() );
  185. meshBuilder.Position3fv (point.Base());
  186. meshBuilder.AdvanceVertex();
  187. meshBuilder.Color4ubv (pColor);
  188. meshBuilder.TexCoord2f (0, 1, 1);
  189. VectorMA (vecOrigin, -flHeight, up, point);
  190. VectorMA (point, flWidth, right, point);
  191. meshBuilder.TangentS3fv( left.Base() );
  192. meshBuilder.TangentT3fv( down.Base() );
  193. meshBuilder.Normal3fv( back.Base() );
  194. meshBuilder.Position3fv (point.Base());
  195. meshBuilder.AdvanceVertex();
  196. meshBuilder.End();
  197. pMesh->Draw();
  198. }
  199. void Gunship_DrawSprite( const Vector &vecOrigin, float size, const color32 &color, bool glow )
  200. {
  201. if ( glow )
  202. {
  203. pixelvis_queryparams_t params;
  204. params.Init( vecOrigin );
  205. if ( PixelVisibility_FractionVisible( params, NULL ) <= 0.0f )
  206. return;
  207. }
  208. DrawSpriteTangentSpace( vecOrigin, size, size, color );
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose:
  212. // Input : int -
  213. //-----------------------------------------------------------------------------
  214. int C_GunshipFX::DrawModel( int )
  215. {
  216. static color32 white = {255,255,255,255};
  217. Vector params[GUNSHIPFX_PARAMETERS];
  218. bool hasParam[GUNSHIPFX_PARAMETERS];
  219. if ( !m_active )
  220. return 1;
  221. C_BaseEntity *ent = cl_entitylist->GetEnt( m_entityIndex );
  222. if ( ent )
  223. {
  224. QAngle angles;
  225. ent->GetAttachment( m_attachment, m_worldPosition, angles );
  226. }
  227. Vector test;
  228. m_t += gpGlobals->frametime;
  229. if ( m_tMax > 0 )
  230. {
  231. m_t = clamp( m_t, 0, m_tMax );
  232. m_beamEndPosition = m_worldPosition;
  233. }
  234. float t = m_t;
  235. bool hasAny = false;
  236. memset( hasParam, 0, sizeof(hasParam) );
  237. for ( int i = 0; i < GUNSHIPFX_PARAMETERS; i++ )
  238. {
  239. hasParam[i] = g_GunshipCannonEnvelope.m_parameters[i].Interp( params[i], t );
  240. hasAny = hasAny || hasParam[i];
  241. }
  242. // draw the narrow beam
  243. if ( hasParam[GUNSHIPFX_NARROW_BEAM_COLOR] && hasParam[GUNSHIPFX_NARROW_BEAM_SIZE] )
  244. {
  245. IMaterial *pMat = materials->FindMaterial( "sprites/bluelaser1", TEXTURE_GROUP_CLIENT_EFFECTS );
  246. float width = NARROW_BEAM_WIDTH * params[GUNSHIPFX_NARROW_BEAM_SIZE].x;
  247. color32 color;
  248. float bright = params[GUNSHIPFX_NARROW_BEAM_COLOR].x;
  249. ScaleColor( color, white, bright );
  250. //Gunship_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color );
  251. FX_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color );
  252. }
  253. // glowy blue flare sprite
  254. if ( hasParam[GUNSHIPFX_FLARE_COLOR] && hasParam[GUNSHIPFX_FLARE_SIZE] )
  255. {
  256. IMaterial *pMat = materials->FindMaterial( "effects/blueblackflash", TEXTURE_GROUP_CLIENT_EFFECTS );
  257. float size = FLARE_SIZE * params[GUNSHIPFX_FLARE_SIZE].x;
  258. color32 color;
  259. float bright = params[GUNSHIPFX_FLARE_COLOR].x;
  260. ScaleColor( color, white, bright );
  261. color.a = (int)(255 * params[GUNSHIPFX_DARKNESS].x);
  262. CMatRenderContextPtr pRenderContext( materials );
  263. pRenderContext->Bind( pMat, (IClientRenderable*)this );
  264. Gunship_DrawSprite( m_worldPosition, size, color, true );
  265. }
  266. if ( hasParam[GUNSHIPFX_AFTERGLOW_COLOR] )
  267. {
  268. // Muzzle effect
  269. dlight_t *dl = effects->CL_AllocDlight( m_entityIndex );
  270. dl->origin = m_worldPosition;
  271. dl->color.r = 40*params[GUNSHIPFX_AFTERGLOW_COLOR].x;
  272. dl->color.g = 60*params[GUNSHIPFX_AFTERGLOW_COLOR].x;
  273. dl->color.b = 255*params[GUNSHIPFX_AFTERGLOW_COLOR].x;
  274. dl->color.exponent = 5;
  275. dl->radius = 128.0f;
  276. dl->die = gpGlobals->curtime + 0.001;
  277. }
  278. if ( m_t >= 4.0 && !hasAny )
  279. {
  280. EffectShutdown();
  281. }
  282. return 1;
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Purpose:
  286. // Input : *pOwner -
  287. // &targetPos -
  288. //-----------------------------------------------------------------------------
  289. void C_GunshipFX::Update( C_BaseEntity *pOwner, const Vector &targetPos )
  290. {
  291. BaseClass::Update();
  292. m_pOwner = pOwner;
  293. if ( m_active )
  294. {
  295. m_targetPosition = targetPos;
  296. }
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Gunship
  300. //-----------------------------------------------------------------------------
  301. class C_CombineGunship : public C_BaseHelicopter
  302. {
  303. DECLARE_CLASS( C_CombineGunship, C_BaseHelicopter );
  304. public:
  305. DECLARE_CLIENTCLASS();
  306. C_CombineGunship( void ) {}
  307. virtual ~C_CombineGunship( void )
  308. {
  309. m_cannonFX.EffectShutdown();
  310. }
  311. C_GunshipFX m_cannonFX;
  312. Vector m_vecHitPos;
  313. //-----------------------------------------------------------------------------
  314. // Purpose:
  315. // Input : length -
  316. // *data -
  317. // Output : void
  318. //-----------------------------------------------------------------------------
  319. void ReceiveMessage( int classID, bf_read &msg )
  320. {
  321. if ( classID != GetClientClass()->m_ClassID )
  322. {
  323. // message is for subclass
  324. BaseClass::ReceiveMessage( classID, msg );
  325. return;
  326. }
  327. int messageType = msg.ReadByte();
  328. switch( messageType )
  329. {
  330. case GUNSHIP_MSG_STREAKS:
  331. {
  332. Vector pos;
  333. msg.ReadBitVec3Coord( pos );
  334. m_cannonFX.SetRenderOrigin( pos );
  335. m_cannonFX.EffectInit( entindex(), LookupAttachment( "BellyGun" ) );
  336. m_cannonFX.LimitTime( GUNSHIPFX_BIG_SHOT_TIME );
  337. }
  338. break;
  339. case GUNSHIP_MSG_BIG_SHOT:
  340. {
  341. Vector tmp;
  342. msg.ReadBitVec3Coord( tmp );
  343. m_cannonFX.SetTime( GUNSHIPFX_BIG_SHOT_TIME );
  344. m_cannonFX.LimitTime( 0 );
  345. }
  346. break;
  347. case GUNSHIP_MSG_DEAD:
  348. {
  349. m_cannonFX.EffectShutdown();
  350. }
  351. break;
  352. }
  353. }
  354. void OnDataChanged( DataUpdateType_t updateType )
  355. {
  356. BaseClass::OnDataChanged( updateType );
  357. m_cannonFX.Update( this, m_vecHitPos );
  358. }
  359. virtual RenderGroup_t GetRenderGroup()
  360. {
  361. if ( hl2_episodic.GetBool() == true )
  362. {
  363. return RENDER_GROUP_TWOPASS;
  364. }
  365. else
  366. {
  367. return BaseClass::GetRenderGroup();
  368. }
  369. }
  370. private:
  371. C_CombineGunship( const C_CombineGunship & ) {}
  372. };
  373. IMPLEMENT_CLIENTCLASS_DT( C_CombineGunship, DT_CombineGunship, CNPC_CombineGunship )
  374. RecvPropVector(RECVINFO(m_vecHitPos)),
  375. END_RECV_TABLE()
  376. //-----------------------------------------------------------------------------
  377. // Purpose: Handle gunship impacts
  378. //-----------------------------------------------------------------------------
  379. void ImpactGunshipCallback( const CEffectData &data )
  380. {
  381. trace_t tr;
  382. Vector vecOrigin, vecStart, vecShotDir;
  383. int iMaterial, iDamageType, iHitbox;
  384. short nSurfaceProp;
  385. C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox );
  386. if ( !pEntity )
  387. return;
  388. // If we hit, perform our custom effects and play the sound
  389. if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) )
  390. {
  391. // Check for custom effects based on the Decal index
  392. PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 3 );
  393. }
  394. PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp );
  395. }
  396. DECLARE_CLIENT_EFFECT( "ImpactGunship", ImpactGunshipCallback );