//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "iefx.h" #include "dlight.h" #include "engine/IEngineSound.h" #include "view.h" #include "beamdraw.h" #include "clienteffectprecachesystem.h" #include "weapon_combat_usedwithshieldbase.h" #include "c_weapon__stubs.h" #include #define BALL_GROW_TIME 1.5 // Precache the effects CLIENTEFFECT_REGISTER_BEGIN( PrecacheWeaponCombat_ChargeablePlasma ) CLIENTEFFECT_MATERIAL( "sprites/chargeball_team1" ) CLIENTEFFECT_MATERIAL( "sprites/chargeball_team2" ) CLIENTEFFECT_REGISTER_END() //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class C_WeaponCombat_ChargeablePlasma : public C_WeaponCombatUsedWithShieldBase { DECLARE_CLASS( C_WeaponCombat_ChargeablePlasma, C_WeaponCombatUsedWithShieldBase ); public: DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); C_WeaponCombat_ChargeablePlasma( void ); ~C_WeaponCombat_ChargeablePlasma( void ); virtual void PreDataUpdate( DataUpdateType_t updateType ); virtual void OnDataChanged( DataUpdateType_t updateType ); virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); virtual void DrawCrosshair( void ); virtual void ClientThink( ); virtual int DrawModel( int flags ); virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel ); virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); virtual bool IsTransparent( ); private: void StartCharging(); void StopCharging(); void DrawChargingEffect( float flSize, C_BaseAnimating *pAttachedEnt ); private: bool m_bCharging; bool m_bLastCharging; float m_flPower; float m_flChargeStartTime; CMaterialReference m_hMaterial; private: C_WeaponCombat_ChargeablePlasma( const C_WeaponCombat_ChargeablePlasma & ); }; STUB_WEAPON_CLASS_IMPLEMENT( weapon_combat_chargeableplasma, C_WeaponCombat_ChargeablePlasma ); IMPLEMENT_CLIENTCLASS_DT( C_WeaponCombat_ChargeablePlasma, DT_WeaponCombat_ChargeablePlasma, CWeaponCombat_ChargeablePlasma ) RecvPropInt( RECVINFO(m_bCharging) ), END_RECV_TABLE() //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- C_WeaponCombat_ChargeablePlasma::C_WeaponCombat_ChargeablePlasma( void ) { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- C_WeaponCombat_ChargeablePlasma::~C_WeaponCombat_ChargeablePlasma( void ) { Holster( NULL ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_WeaponCombat_ChargeablePlasma::PreDataUpdate( DataUpdateType_t updateType ) { BaseClass::PreDataUpdate( updateType ); m_bLastCharging = m_bCharging; } void C_WeaponCombat_ChargeablePlasma::NotifyShouldTransmit( ShouldTransmitState_t state ) { BaseClass::NotifyShouldTransmit(state); if (state == SHOULDTRANSMIT_START) { if (m_bCharging) StartCharging(); } else if (state == SHOULDTRANSMIT_END) { if (m_bCharging) StopCharging(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_WeaponCombat_ChargeablePlasma::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); switch( updateType ) { case DATA_UPDATE_CREATED: // So we can update our lights if ( GetTeamNumber() == 1 ) m_hMaterial.Init( "sprites/chargeball_team1" ); else m_hMaterial.Init( "sprites/chargeball_team2" ); break; case DATA_UPDATE_DATATABLE_CHANGED: if ( m_bCharging != m_bLastCharging ) { if ( m_bCharging ) { StartCharging(); } else { StopCharging(); } } break; }; if (WeaponState() == WEAPON_IS_ACTIVE) { // Start thinking so we can manipulate the light SetNextClientThink( CLIENT_THINK_ALWAYS ); } else { SetNextClientThink( CLIENT_THINK_NEVER ); } } //----------------------------------------------------------------------------- // Deal with dynamic lighting //----------------------------------------------------------------------------- void C_WeaponCombat_ChargeablePlasma::ClientThink( ) { BaseClass::ClientThink(); C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)GetOwner(); if ( !pPlayer || (pPlayer->GetHealth() <= 0)) { SetNextClientThink( CLIENT_THINK_NEVER ); return; } if (!m_bCharging) return; // Determine the ball size... m_flPower = (gpGlobals->curtime - m_flChargeStartTime) / BALL_GROW_TIME; m_flPower = clamp( m_flPower, 0, 1 ); // FIXME: dl->origin should be based on the attachment point dlight_t *dl = effects->CL_AllocDlight( entindex() ); dl->origin = GetRenderOrigin(); if (GetTeamNumber() == 1) { dl->color.r = 40; dl->color.g = 60; dl->color.b = 250; } else { dl->color.r = 250; dl->color.g = 60; dl->color.b = 40; } dl->color.exponent = 5; dl->radius = 20 * m_flPower + 10; dl->die = gpGlobals->curtime + 0.01; } //----------------------------------------------------------------------------- // Purpose: Remove the ball if we're switching away //----------------------------------------------------------------------------- bool C_WeaponCombat_ChargeablePlasma::Holster( C_BaseCombatWeapon *pSwitchingTo ) { StopCharging(); return BaseClass::Holster( pSwitchingTo ); } void C_WeaponCombat_ChargeablePlasma::StartCharging() { CLocalPlayerFilter filter; EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "WeaponCombat_ChargeablePlasma.Charging" ); m_flChargeStartTime = gpGlobals->curtime; } void C_WeaponCombat_ChargeablePlasma::StopCharging() { StopSound( SOUND_FROM_LOCAL_PLAYER, "WeaponCombat_ChargeablePlasma.Charging" ); m_bCharging = false; } //----------------------------------------------------------------------------- // We're transparent because we draw a transparent charging effect //----------------------------------------------------------------------------- bool C_WeaponCombat_ChargeablePlasma::IsTransparent( ) { if (m_bCharging) return true; return BaseClass::IsTransparent(); } //----------------------------------------------------------------------------- // Purpose: Draws the charging effect //----------------------------------------------------------------------------- void C_WeaponCombat_ChargeablePlasma::DrawChargingEffect( float flSize, C_BaseAnimating *pAttachedEnt ) { if (!pAttachedEnt) return; Vector vecOrigin; QAngle vecAngles; int iAttachment = pAttachedEnt->LookupAttachment( "muzzle" ); if ( pAttachedEnt->GetAttachment( iAttachment, vecOrigin, vecAngles ) ) { color32 color = { 255, 255, 255, 255 }; materials->Bind( m_hMaterial, (IClientRenderable*)this ); DrawSprite( vecOrigin, flSize, flSize, color ); } } //----------------------------------------------------------------------------- // Purpose: Draws the model //----------------------------------------------------------------------------- int C_WeaponCombat_ChargeablePlasma::DrawModel( int flags ) { int retval = BaseClass::DrawModel( flags ); if (retval == 0) return 0; if (m_bCharging && IsCarrierAlive()) { // Draw the charging effect float flSize = 20 * m_flPower + 10; DrawChargingEffect( flSize, this ); } return retval; } //----------------------------------------------------------------------------- // Purpose: Draws the model //----------------------------------------------------------------------------- void C_WeaponCombat_ChargeablePlasma::ViewModelDrawn( C_BaseViewModel *pBaseViewModel ) { if (!m_bCharging) return; // Draw the charging effect float flSize = 12 * m_flPower + 6; if ( m_iClip1 > 0 ) { DrawChargingEffect( flSize, pBaseViewModel ); } } //----------------------------------------------------------------------------- // Purpose: Draw targeting reticle //----------------------------------------------------------------------------- void C_WeaponCombat_ChargeablePlasma::DrawCrosshair( void ) { BaseClass::DrawCrosshair(); // Find enemy players in front of me C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) return; trace_t tr; Vector vecStart, vecEnd; VectorMA( CurrentViewOrigin(), 1500, CurrentViewForward(), vecEnd ); VectorMA( CurrentViewOrigin(), 48, CurrentViewForward(), vecStart ); UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr ); if ( tr.DidHitNonWorldEntity() ) { C_BaseEntity *pEntity = tr.m_pEnt; if ( pEntity && pEntity->IsPlayer() && !pPlayer->InSameTeam( pEntity ) ) { // Draw a reticle vgui::Color clr = gHUD.m_clrYellowish; clr[3] = 128; // Calculate circle size int iRatio = 30; // Draw the circle int iDegrees = 0; Vector vecPoint, vecLastPoint(0,0,0); vecPoint.z = 0.0f; for ( int i = 0; i < 360; i++ ) { float flRadians = DEG2RAD( iDegrees ); iDegrees += (360 / 360); float ca = cos( flRadians ); float sa = sin( flRadians ); // Rotate it around the circle vecPoint.x = (int)((ScreenWidth() / 2) + (iRatio * sa)); vecPoint.y = (int)((ScreenHeight() / 2) - (iRatio * ca)); // Draw the point, if it's not on the previous point, to avoid smaller circles being brighter if ( vecLastPoint != vecPoint ) { vgui::surface()->DrawSetColor( clr ); vgui::surface()->DrawFilledRect( vecPoint.x, vecPoint.y, vecPoint.x + 1, vecPoint.y + 1 ); } vecLastPoint = vecPoint; } } } }