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.

901 lines
25 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Stun Stick- beating stick with a zappy end
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "npcevent.h"
  9. #include "weapon_hl2mpbasebasebludgeon.h"
  10. #include "IEffects.h"
  11. #include "debugoverlay_shared.h"
  12. #ifndef CLIENT_DLL
  13. #include "npc_metropolice.h"
  14. #include "te_effect_dispatch.h"
  15. #endif
  16. #ifdef CLIENT_DLL
  17. #include "iviewrender_beams.h"
  18. #include "beam_shared.h"
  19. #include "materialsystem/imaterial.h"
  20. #include "model_types.h"
  21. #include "c_te_effect_dispatch.h"
  22. #include "fx_quad.h"
  23. #include "fx.h"
  24. extern void DrawHalo( IMaterial* pMaterial, const Vector &source, float scale, float const *color, float flHDRColorScale );
  25. extern void FormatViewModelAttachment( Vector &vOrigin, bool bInverse );
  26. #endif
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include "tier0/memdbgon.h"
  29. extern ConVar metropolice_move_and_melee;
  30. #define STUNSTICK_RANGE 75.0f
  31. #define STUNSTICK_REFIRE 0.8f
  32. #define STUNSTICK_BEAM_MATERIAL "sprites/lgtning.vmt"
  33. #define STUNSTICK_GLOW_MATERIAL "sprites/light_glow02_add"
  34. #define STUNSTICK_GLOW_MATERIAL2 "effects/blueflare1"
  35. #define STUNSTICK_GLOW_MATERIAL_NOZ "sprites/light_glow02_add_noz"
  36. #ifdef CLIENT_DLL
  37. #define CWeaponStunStick C_WeaponStunStick
  38. #endif
  39. class CWeaponStunStick : public CBaseHL2MPBludgeonWeapon
  40. {
  41. DECLARE_CLASS( CWeaponStunStick, CBaseHL2MPBludgeonWeapon );
  42. public:
  43. CWeaponStunStick();
  44. DECLARE_NETWORKCLASS();
  45. DECLARE_PREDICTABLE();
  46. #ifndef CLIENT_DLL
  47. DECLARE_ACTTABLE();
  48. #endif
  49. #ifdef CLIENT_DLL
  50. virtual int DrawModel( int flags );
  51. virtual void ClientThink( void );
  52. virtual void OnDataChanged( DataUpdateType_t updateType );
  53. virtual RenderGroup_t GetRenderGroup( void );
  54. virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel );
  55. #endif
  56. virtual void Precache();
  57. void Spawn();
  58. float GetRange( void ) { return STUNSTICK_RANGE; }
  59. float GetFireRate( void ) { return STUNSTICK_REFIRE; }
  60. bool Deploy( void );
  61. bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
  62. void Drop( const Vector &vecVelocity );
  63. void ImpactEffect( trace_t &traceHit );
  64. void SecondaryAttack( void ) {}
  65. void SetStunState( bool state );
  66. bool GetStunState( void );
  67. #ifndef CLIENT_DLL
  68. void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
  69. int WeaponMeleeAttack1Condition( float flDot, float flDist );
  70. #endif
  71. float GetDamageForActivity( Activity hitActivity );
  72. CWeaponStunStick( const CWeaponStunStick & );
  73. private:
  74. #ifdef CLIENT_DLL
  75. #define NUM_BEAM_ATTACHMENTS 9
  76. struct stunstickBeamInfo_t
  77. {
  78. int IDs[2]; // 0 - top, 1 - bottom
  79. };
  80. stunstickBeamInfo_t m_BeamAttachments[NUM_BEAM_ATTACHMENTS]; // Lookup for arc attachment points on the head of the stick
  81. int m_BeamCenterAttachment; // "Core" of the effect (center of the head)
  82. void SetupAttachmentPoints( void );
  83. void DrawFirstPersonEffects( void );
  84. void DrawThirdPersonEffects( void );
  85. void DrawEffects( void );
  86. bool InSwing( void );
  87. bool m_bSwungLastFrame;
  88. #define FADE_DURATION 0.25f
  89. float m_flFadeTime;
  90. #endif
  91. CNetworkVar( bool, m_bActive );
  92. };
  93. //-----------------------------------------------------------------------------
  94. // CWeaponStunStick
  95. //-----------------------------------------------------------------------------
  96. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponStunStick, DT_WeaponStunStick )
  97. BEGIN_NETWORK_TABLE( CWeaponStunStick, DT_WeaponStunStick )
  98. #ifdef CLIENT_DLL
  99. RecvPropInt( RECVINFO( m_bActive ) ),
  100. #else
  101. SendPropInt( SENDINFO( m_bActive ), 1, SPROP_UNSIGNED ),
  102. #endif
  103. END_NETWORK_TABLE()
  104. BEGIN_PREDICTION_DATA( CWeaponStunStick )
  105. END_PREDICTION_DATA()
  106. LINK_ENTITY_TO_CLASS( weapon_stunstick, CWeaponStunStick );
  107. PRECACHE_WEAPON_REGISTER( weapon_stunstick );
  108. #ifndef CLIENT_DLL
  109. acttable_t CWeaponStunStick::m_acttable[] =
  110. {
  111. { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },
  112. { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_MELEE, false },
  113. { ACT_HL2MP_RUN, ACT_HL2MP_RUN_MELEE, false },
  114. { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_MELEE, false },
  115. { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_MELEE, false },
  116. { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false },
  117. { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false },
  118. { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false },
  119. };
  120. IMPLEMENT_ACTTABLE(CWeaponStunStick);
  121. #endif
  122. //-----------------------------------------------------------------------------
  123. // Constructor
  124. //-----------------------------------------------------------------------------
  125. CWeaponStunStick::CWeaponStunStick( void )
  126. {
  127. // HACK: Don't call SetStunState because this tried to Emit a sound before
  128. // any players are connected which is a bug
  129. m_bActive = false;
  130. #ifdef CLIENT_DLL
  131. m_bSwungLastFrame = false;
  132. m_flFadeTime = FADE_DURATION; // Start off past the fade point
  133. #endif
  134. }
  135. //-----------------------------------------------------------------------------
  136. //-----------------------------------------------------------------------------
  137. void CWeaponStunStick::Spawn()
  138. {
  139. Precache();
  140. BaseClass::Spawn();
  141. AddSolidFlags( FSOLID_NOT_STANDABLE );
  142. }
  143. void CWeaponStunStick::Precache()
  144. {
  145. BaseClass::Precache();
  146. PrecacheScriptSound( "Weapon_StunStick.Activate" );
  147. PrecacheScriptSound( "Weapon_StunStick.Deactivate" );
  148. PrecacheModel( STUNSTICK_BEAM_MATERIAL );
  149. PrecacheModel( "sprites/light_glow02_add.vmt" );
  150. PrecacheModel( "effects/blueflare1.vmt" );
  151. PrecacheModel( "sprites/light_glow02_add_noz.vmt" );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: Get the damage amount for the animation we're doing
  155. // Input : hitActivity - currently played activity
  156. // Output : Damage amount
  157. //-----------------------------------------------------------------------------
  158. float CWeaponStunStick::GetDamageForActivity( Activity hitActivity )
  159. {
  160. return 40.0f;
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!)
  164. //-----------------------------------------------------------------------------
  165. extern ConVar sk_crowbar_lead_time;
  166. //-----------------------------------------------------------------------------
  167. // Purpose:
  168. //-----------------------------------------------------------------------------
  169. void CWeaponStunStick::ImpactEffect( trace_t &traceHit )
  170. {
  171. //#ifndef CLIENT_DLL
  172. CEffectData data;
  173. data.m_vNormal = traceHit.plane.normal;
  174. data.m_vOrigin = traceHit.endpos + ( data.m_vNormal * 4.0f );
  175. DispatchEffect( "StunstickImpact", data );
  176. //#endif
  177. //FIXME: need new decals
  178. UTIL_ImpactTrace( &traceHit, DMG_CLUB );
  179. }
  180. #ifndef CLIENT_DLL
  181. int CWeaponStunStick::WeaponMeleeAttack1Condition( float flDot, float flDist )
  182. {
  183. // Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!)
  184. CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer();
  185. CBaseEntity *pEnemy = pNPC->GetEnemy();
  186. if (!pEnemy)
  187. return COND_NONE;
  188. Vector vecVelocity;
  189. AngularImpulse angVelocity;
  190. pEnemy->GetVelocity( &vecVelocity, &angVelocity );
  191. // Project where the enemy will be in a little while, add some randomness so he doesn't always hit
  192. float dt = sk_crowbar_lead_time.GetFloat();
  193. dt += random->RandomFloat( -0.3f, 0.2f );
  194. if ( dt < 0.0f )
  195. dt = 0.0f;
  196. Vector vecExtrapolatedPos;
  197. VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos );
  198. Vector vecDelta;
  199. VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta );
  200. if ( fabs( vecDelta.z ) > 70 )
  201. {
  202. return COND_TOO_FAR_TO_ATTACK;
  203. }
  204. Vector vecForward = pNPC->BodyDirection2D( );
  205. vecDelta.z = 0.0f;
  206. float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() );
  207. if ((flDot < 0.7) && (flExtrapolatedDot < 0.7))
  208. {
  209. return COND_NOT_FACING_ATTACK;
  210. }
  211. float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() );
  212. if( pEnemy->IsPlayer() )
  213. {
  214. //Vector vecDir = pEnemy->GetSmoothedVelocity();
  215. //float flSpeed = VectorNormalize( vecDir );
  216. // If player will be in front of me in one-half second, clock his arse.
  217. Vector vecProjectEnemy = pEnemy->GetAbsOrigin() + (pEnemy->GetAbsVelocity() * 0.35);
  218. Vector vecProjectMe = GetAbsOrigin();
  219. if( (vecProjectMe - vecProjectEnemy).Length2D() <= 48.0f )
  220. {
  221. return COND_CAN_MELEE_ATTACK1;
  222. }
  223. }
  224. /*
  225. if( metropolice_move_and_melee.GetBool() )
  226. {
  227. if( pNPC->IsMoving() )
  228. {
  229. flTargetDist *= 1.5f;
  230. }
  231. }
  232. */
  233. float flTargetDist = 48.0f;
  234. if ((flDist > flTargetDist) && (flExtrapolatedDist > flTargetDist))
  235. {
  236. return COND_TOO_FAR_TO_ATTACK;
  237. }
  238. return COND_CAN_MELEE_ATTACK1;
  239. }
  240. void CWeaponStunStick::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
  241. {
  242. switch( pEvent->event )
  243. {
  244. case EVENT_WEAPON_MELEE_HIT:
  245. {
  246. // Trace up or down based on where the enemy is...
  247. // But only if we're basically facing that direction
  248. Vector vecDirection;
  249. AngleVectors( GetAbsAngles(), &vecDirection );
  250. CBaseEntity *pEnemy = pOperator->MyNPCPointer() ? pOperator->MyNPCPointer()->GetEnemy() : NULL;
  251. if ( pEnemy )
  252. {
  253. Vector vecDelta;
  254. VectorSubtract( pEnemy->WorldSpaceCenter(), pOperator->Weapon_ShootPosition(), vecDelta );
  255. VectorNormalize( vecDelta );
  256. Vector2D vecDelta2D = vecDelta.AsVector2D();
  257. Vector2DNormalize( vecDelta2D );
  258. if ( DotProduct2D( vecDelta2D, vecDirection.AsVector2D() ) > 0.8f )
  259. {
  260. vecDirection = vecDelta;
  261. }
  262. }
  263. Vector vecEnd;
  264. VectorMA( pOperator->Weapon_ShootPosition(), 32, vecDirection, vecEnd );
  265. // Stretch the swing box down to catch low level physics objects
  266. CBaseEntity *pHurt = pOperator->CheckTraceHullAttack( pOperator->Weapon_ShootPosition(), vecEnd,
  267. Vector(-16,-16,-40), Vector(16,16,16), GetDamageForActivity( GetActivity() ), DMG_CLUB, 0.5f, false );
  268. // did I hit someone?
  269. if ( pHurt )
  270. {
  271. // play sound
  272. WeaponSound( MELEE_HIT );
  273. CBasePlayer *pPlayer = ToBasePlayer( pHurt );
  274. bool bFlashed = false;
  275. // Punch angles
  276. if ( pPlayer != NULL && !(pPlayer->GetFlags() & FL_GODMODE) )
  277. {
  278. float yawKick = random->RandomFloat( -48, -24 );
  279. //Kick the player angles
  280. pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) );
  281. Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin();
  282. // If the player's on my head, don't knock him up
  283. if ( pPlayer->GetGroundEntity() == pOperator )
  284. {
  285. dir = vecDirection;
  286. dir.z = 0;
  287. }
  288. VectorNormalize(dir);
  289. dir *= 500.0f;
  290. //If not on ground, then don't make them fly!
  291. if ( !(pPlayer->GetFlags() & FL_ONGROUND ) )
  292. dir.z = 0.0f;
  293. //Push the target back
  294. pHurt->ApplyAbsVelocityImpulse( dir );
  295. if ( !bFlashed )
  296. {
  297. color32 red = {128,0,0,128};
  298. UTIL_ScreenFade( pPlayer, red, 0.5f, 0.1f, FFADE_IN );
  299. }
  300. // Force the player to drop anyting they were holding
  301. pPlayer->ForceDropOfCarriedPhysObjects();
  302. }
  303. // do effect?
  304. }
  305. else
  306. {
  307. WeaponSound( MELEE_MISS );
  308. }
  309. }
  310. break;
  311. default:
  312. BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
  313. break;
  314. }
  315. }
  316. #endif
  317. //-----------------------------------------------------------------------------
  318. // Purpose: Sets the state of the stun stick
  319. //-----------------------------------------------------------------------------
  320. void CWeaponStunStick::SetStunState( bool state )
  321. {
  322. m_bActive = state;
  323. if ( m_bActive )
  324. {
  325. //FIXME: START - Move to client-side
  326. Vector vecAttachment;
  327. QAngle vecAttachmentAngles;
  328. GetAttachment( 1, vecAttachment, vecAttachmentAngles );
  329. g_pEffects->Sparks( vecAttachment );
  330. //FIXME: END - Move to client-side
  331. EmitSound( "Weapon_StunStick.Activate" );
  332. }
  333. else
  334. {
  335. EmitSound( "Weapon_StunStick.Deactivate" );
  336. }
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Purpose:
  340. // Output : Returns true on success, false on failure.
  341. //-----------------------------------------------------------------------------
  342. bool CWeaponStunStick::Deploy( void )
  343. {
  344. SetStunState( true );
  345. return BaseClass::Deploy();
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose:
  349. //-----------------------------------------------------------------------------
  350. bool CWeaponStunStick::Holster( CBaseCombatWeapon *pSwitchingTo )
  351. {
  352. if ( BaseClass::Holster( pSwitchingTo ) == false )
  353. return false;
  354. SetStunState( false );
  355. SetWeaponVisible( false );
  356. return true;
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Purpose:
  360. // Input : &vecVelocity -
  361. //-----------------------------------------------------------------------------
  362. void CWeaponStunStick::Drop( const Vector &vecVelocity )
  363. {
  364. SetStunState( false );
  365. #ifndef CLIENT_DLL
  366. UTIL_Remove( this );
  367. #endif
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Purpose:
  371. // Output : Returns true on success, false on failure.
  372. //-----------------------------------------------------------------------------
  373. bool CWeaponStunStick::GetStunState( void )
  374. {
  375. return m_bActive;
  376. }
  377. #ifdef CLIENT_DLL
  378. //-----------------------------------------------------------------------------
  379. // Purpose: Get the attachment point on a viewmodel that a base weapon is using
  380. //-----------------------------------------------------------------------------
  381. bool UTIL_GetWeaponAttachment( C_BaseCombatWeapon *pWeapon, int attachmentID, Vector &absOrigin, QAngle &absAngles )
  382. {
  383. // This is already correct in third-person
  384. if ( pWeapon && pWeapon->ShouldDrawUsingViewModel() == false )
  385. {
  386. return pWeapon->GetAttachment( attachmentID, absOrigin, absAngles );
  387. }
  388. // Otherwise we need to translate the attachment to the viewmodel's version and reformat it
  389. CBasePlayer *pOwner = ToBasePlayer( pWeapon->GetOwner() );
  390. if ( pOwner != NULL )
  391. {
  392. int ret = pOwner->GetViewModel()->GetAttachment( attachmentID, absOrigin, absAngles );
  393. FormatViewModelAttachment( absOrigin, true );
  394. return ret;
  395. }
  396. // Wasn't found
  397. return false;
  398. }
  399. #define BEAM_ATTACH_CORE_NAME "sparkrear"
  400. //-----------------------------------------------------------------------------
  401. // Purpose: Sets up the attachment point lookup for the model
  402. //-----------------------------------------------------------------------------
  403. void C_WeaponStunStick::SetupAttachmentPoints( void )
  404. {
  405. // Setup points for both types of views
  406. if ( ShouldDrawUsingViewModel() )
  407. {
  408. const char *szBeamAttachNamesTop[NUM_BEAM_ATTACHMENTS] =
  409. {
  410. "spark1a","spark2a","spark3a","spark4a",
  411. "spark5a","spark6a","spark7a","spark8a",
  412. "spark9a",
  413. };
  414. const char *szBeamAttachNamesBottom[NUM_BEAM_ATTACHMENTS] =
  415. {
  416. "spark1b","spark2b","spark3b","spark4b",
  417. "spark5b","spark6b","spark7b","spark8b",
  418. "spark9b",
  419. };
  420. // Lookup and store all connections
  421. for ( int i = 0; i < NUM_BEAM_ATTACHMENTS; i++ )
  422. {
  423. m_BeamAttachments[i].IDs[0] = LookupAttachment( szBeamAttachNamesTop[i] );
  424. m_BeamAttachments[i].IDs[1] = LookupAttachment( szBeamAttachNamesBottom[i] );
  425. }
  426. // Setup the center beam point
  427. m_BeamCenterAttachment = LookupAttachment( BEAM_ATTACH_CORE_NAME );
  428. }
  429. else
  430. {
  431. // Setup the center beam point
  432. m_BeamCenterAttachment = 1;
  433. }
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose: Draws the stunstick model (with extra effects)
  437. //-----------------------------------------------------------------------------
  438. int C_WeaponStunStick::DrawModel( int flags )
  439. {
  440. if ( ShouldDraw() == false )
  441. return 0;
  442. // Only render these on the transparent pass
  443. if ( flags & STUDIO_TRANSPARENCY )
  444. {
  445. DrawEffects();
  446. return 1;
  447. }
  448. return BaseClass::DrawModel( flags );
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose: Randomly adds extra effects
  452. //-----------------------------------------------------------------------------
  453. void C_WeaponStunStick::ClientThink( void )
  454. {
  455. if ( InSwing() == false )
  456. {
  457. if ( m_bSwungLastFrame )
  458. {
  459. // Start fading
  460. m_flFadeTime = gpGlobals->curtime;
  461. m_bSwungLastFrame = false;
  462. }
  463. return;
  464. }
  465. // Remember if we were swinging last frame
  466. m_bSwungLastFrame = InSwing();
  467. if ( IsEffectActive( EF_NODRAW ) )
  468. return;
  469. if ( ShouldDrawUsingViewModel() )
  470. {
  471. // Update our effects
  472. if ( gpGlobals->frametime != 0.0f && ( random->RandomInt( 0, 3 ) == 0 ) )
  473. {
  474. Vector vecOrigin;
  475. QAngle vecAngles;
  476. // Inner beams
  477. BeamInfo_t beamInfo;
  478. int attachment = random->RandomInt( 0, 15 );
  479. UTIL_GetWeaponAttachment( this, attachment, vecOrigin, vecAngles );
  480. ::FormatViewModelAttachment( vecOrigin, false );
  481. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  482. CBaseEntity *pBeamEnt = pOwner->GetViewModel();
  483. beamInfo.m_vecStart = vec3_origin;
  484. beamInfo.m_pStartEnt= pBeamEnt;
  485. beamInfo.m_nStartAttachment = attachment;
  486. beamInfo.m_pEndEnt = NULL;
  487. beamInfo.m_nEndAttachment = -1;
  488. beamInfo.m_vecEnd = vecOrigin + RandomVector( -8, 8 );
  489. beamInfo.m_pszModelName = STUNSTICK_BEAM_MATERIAL;
  490. beamInfo.m_flHaloScale = 0.0f;
  491. beamInfo.m_flLife = 0.05f;
  492. beamInfo.m_flWidth = random->RandomFloat( 1.0f, 2.0f );
  493. beamInfo.m_flEndWidth = 0;
  494. beamInfo.m_flFadeLength = 0.0f;
  495. beamInfo.m_flAmplitude = random->RandomFloat( 16, 32 );
  496. beamInfo.m_flBrightness = 255.0;
  497. beamInfo.m_flSpeed = 0.0;
  498. beamInfo.m_nStartFrame = 0.0;
  499. beamInfo.m_flFrameRate = 1.0f;
  500. beamInfo.m_flRed = 255.0f;;
  501. beamInfo.m_flGreen = 255.0f;
  502. beamInfo.m_flBlue = 255.0f;
  503. beamInfo.m_nSegments = 16;
  504. beamInfo.m_bRenderable = true;
  505. beamInfo.m_nFlags = 0;
  506. beams->CreateBeamEntPoint( beamInfo );
  507. }
  508. }
  509. }
  510. //-----------------------------------------------------------------------------
  511. // Purpose: Starts the client-side version thinking
  512. //-----------------------------------------------------------------------------
  513. void C_WeaponStunStick::OnDataChanged( DataUpdateType_t updateType )
  514. {
  515. BaseClass::OnDataChanged( updateType );
  516. if ( updateType == DATA_UPDATE_CREATED )
  517. {
  518. SetNextClientThink( CLIENT_THINK_ALWAYS );
  519. SetupAttachmentPoints();
  520. }
  521. }
  522. //-----------------------------------------------------------------------------
  523. // Purpose: Tells us we're always a translucent entity
  524. //-----------------------------------------------------------------------------
  525. RenderGroup_t C_WeaponStunStick::GetRenderGroup( void )
  526. {
  527. return RENDER_GROUP_TWOPASS;
  528. }
  529. //-----------------------------------------------------------------------------
  530. // Purpose: Tells us we're always a translucent entity
  531. //-----------------------------------------------------------------------------
  532. bool C_WeaponStunStick::InSwing( void )
  533. {
  534. int activity = GetActivity();
  535. // FIXME: This is needed until the actual animation works
  536. if ( ShouldDrawUsingViewModel() == false )
  537. return true;
  538. // These are the swing activities this weapon can play
  539. if ( activity == GetPrimaryAttackActivity() ||
  540. activity == GetSecondaryAttackActivity() ||
  541. activity == ACT_VM_MISSCENTER ||
  542. activity == ACT_VM_MISSCENTER2 )
  543. return true;
  544. return false;
  545. }
  546. //-----------------------------------------------------------------------------
  547. // Purpose: Draw our special effects
  548. //-----------------------------------------------------------------------------
  549. void C_WeaponStunStick::DrawThirdPersonEffects( void )
  550. {
  551. Vector vecOrigin;
  552. QAngle vecAngles;
  553. float color[3];
  554. float scale;
  555. CMatRenderContextPtr pRenderContext( materials );
  556. IMaterial *pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL, NULL, false );
  557. pRenderContext->Bind( pMaterial );
  558. // Get bright when swung
  559. if ( InSwing() )
  560. {
  561. color[0] = color[1] = color[2] = 0.4f;
  562. scale = 22.0f;
  563. }
  564. else
  565. {
  566. color[0] = color[1] = color[2] = 0.1f;
  567. scale = 20.0f;
  568. }
  569. // Draw an all encompassing glow around the entire head
  570. UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles );
  571. DrawHalo( pMaterial, vecOrigin, scale, color );
  572. if ( InSwing() )
  573. {
  574. pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL2, NULL, false );
  575. pRenderContext->Bind( pMaterial );
  576. color[0] = color[1] = color[2] = random->RandomFloat( 0.6f, 0.8f );
  577. scale = random->RandomFloat( 4.0f, 6.0f );
  578. // Draw an all encompassing glow around the entire head
  579. UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles );
  580. DrawHalo( pMaterial, vecOrigin, scale, color );
  581. // Update our effects
  582. if ( gpGlobals->frametime != 0.0f && ( random->RandomInt( 0, 5 ) == 0 ) )
  583. {
  584. Vector vecOrigin;
  585. QAngle vecAngles;
  586. GetAttachment( 1, vecOrigin, vecAngles );
  587. Vector vForward;
  588. AngleVectors( vecAngles, &vForward );
  589. Vector vEnd = vecOrigin - vForward * 1.0f;
  590. // Inner beams
  591. BeamInfo_t beamInfo;
  592. beamInfo.m_vecStart = vEnd;
  593. Vector offset = RandomVector( -12, 8 );
  594. offset += Vector(4,4,4);
  595. beamInfo.m_vecEnd = vecOrigin + offset;
  596. beamInfo.m_pStartEnt= cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) );
  597. beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) );
  598. beamInfo.m_nStartAttachment = 1;
  599. beamInfo.m_nEndAttachment = -1;
  600. beamInfo.m_nType = TE_BEAMTESLA;
  601. beamInfo.m_pszModelName = STUNSTICK_BEAM_MATERIAL;
  602. beamInfo.m_flHaloScale = 0.0f;
  603. beamInfo.m_flLife = 0.01f;
  604. beamInfo.m_flWidth = random->RandomFloat( 1.0f, 3.0f );
  605. beamInfo.m_flEndWidth = 0;
  606. beamInfo.m_flFadeLength = 0.0f;
  607. beamInfo.m_flAmplitude = random->RandomFloat( 1, 2 );
  608. beamInfo.m_flBrightness = 255.0;
  609. beamInfo.m_flSpeed = 0.0;
  610. beamInfo.m_nStartFrame = 0.0;
  611. beamInfo.m_flFrameRate = 1.0f;
  612. beamInfo.m_flRed = 255.0f;;
  613. beamInfo.m_flGreen = 255.0f;
  614. beamInfo.m_flBlue = 255.0f;
  615. beamInfo.m_nSegments = 16;
  616. beamInfo.m_bRenderable = true;
  617. beamInfo.m_nFlags = FBEAM_SHADEOUT;
  618. beams->CreateBeamPoints( beamInfo );
  619. }
  620. }
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Purpose: Draw our special effects
  624. //-----------------------------------------------------------------------------
  625. void C_WeaponStunStick::DrawFirstPersonEffects( void )
  626. {
  627. Vector vecOrigin;
  628. QAngle vecAngles;
  629. float color[3];
  630. float scale;
  631. CMatRenderContextPtr pRenderContext( materials );
  632. IMaterial *pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL_NOZ, NULL, false );
  633. // FIXME: Needs to work with new IMaterial system!
  634. pRenderContext->Bind( pMaterial );
  635. // Find where we are in the fade
  636. float fadeAmount = RemapValClamped( gpGlobals->curtime, m_flFadeTime, m_flFadeTime + FADE_DURATION, 1.0f, 0.1f );
  637. // Get bright when swung
  638. if ( InSwing() )
  639. {
  640. color[0] = color[1] = color[2] = 0.4f;
  641. scale = 22.0f;
  642. }
  643. else
  644. {
  645. color[0] = color[1] = color[2] = 0.4f * fadeAmount;
  646. scale = 20.0f;
  647. }
  648. if ( color[0] > 0.0f )
  649. {
  650. // Draw an all encompassing glow around the entire head
  651. UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles );
  652. DrawHalo( pMaterial, vecOrigin, scale, color );
  653. }
  654. // Draw bright points at each attachment location
  655. for ( int i = 0; i < (NUM_BEAM_ATTACHMENTS*2)+1; i++ )
  656. {
  657. if ( InSwing() )
  658. {
  659. color[0] = color[1] = color[2] = random->RandomFloat( 0.05f, 0.5f );
  660. scale = random->RandomFloat( 4.0f, 5.0f );
  661. }
  662. else
  663. {
  664. color[0] = color[1] = color[2] = random->RandomFloat( 0.05f, 0.5f ) * fadeAmount;
  665. scale = random->RandomFloat( 4.0f, 5.0f ) * fadeAmount;
  666. }
  667. if ( color[0] > 0.0f )
  668. {
  669. UTIL_GetWeaponAttachment( this, i, vecOrigin, vecAngles );
  670. DrawHalo( pMaterial, vecOrigin, scale, color );
  671. }
  672. }
  673. }
  674. //-----------------------------------------------------------------------------
  675. // Purpose: Draw our special effects
  676. //-----------------------------------------------------------------------------
  677. void C_WeaponStunStick::DrawEffects( void )
  678. {
  679. if ( ShouldDrawUsingViewModel() )
  680. {
  681. DrawFirstPersonEffects();
  682. }
  683. else
  684. {
  685. DrawThirdPersonEffects();
  686. }
  687. }
  688. //-----------------------------------------------------------------------------
  689. // Purpose: Viewmodel was drawn
  690. //-----------------------------------------------------------------------------
  691. void C_WeaponStunStick::ViewModelDrawn( C_BaseViewModel *pBaseViewModel )
  692. {
  693. // Don't bother when we're not deployed
  694. if ( IsWeaponVisible() )
  695. {
  696. // Do all our special effects
  697. DrawEffects();
  698. }
  699. BaseClass::ViewModelDrawn( pBaseViewModel );
  700. }
  701. //-----------------------------------------------------------------------------
  702. // Purpose: Draw a cheap glow quad at our impact point (with sparks)
  703. //-----------------------------------------------------------------------------
  704. void StunstickImpactCallback( const CEffectData &data )
  705. {
  706. float scale = random->RandomFloat( 16, 32 );
  707. FX_AddQuad( data.m_vOrigin,
  708. data.m_vNormal,
  709. scale,
  710. scale*2.0f,
  711. 1.0f,
  712. 1.0f,
  713. 0.0f,
  714. 0.0f,
  715. random->RandomInt( 0, 360 ),
  716. 0,
  717. Vector( 1.0f, 1.0f, 1.0f ),
  718. 0.1f,
  719. "sprites/light_glow02_add",
  720. 0 );
  721. FX_Sparks( data.m_vOrigin, 1, 2, data.m_vNormal, 6, 64, 256 );
  722. }
  723. DECLARE_CLIENT_EFFECT( "StunstickImpact", StunstickImpactCallback );
  724. #endif