summaryrefslogtreecommitdiff
path: root/game/shared/tf2/weapon_combat_plasmarifle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/tf2/weapon_combat_plasmarifle.cpp')
-rw-r--r--game/shared/tf2/weapon_combat_plasmarifle.cpp559
1 files changed, 559 insertions, 0 deletions
diff --git a/game/shared/tf2/weapon_combat_plasmarifle.cpp b/game/shared/tf2/weapon_combat_plasmarifle.cpp
new file mode 100644
index 0000000..2ede901
--- /dev/null
+++ b/game/shared/tf2/weapon_combat_plasmarifle.cpp
@@ -0,0 +1,559 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Chargeable Plasma & Shield combo
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "basetfplayer_shared.h"
+#include "weapon_combatshield.h"
+#include "in_buttons.h"
+#include "weapon_combat_usedwithshieldbase.h"
+#include "plasmaprojectile.h"
+#include "in_buttons.h"
+#include "tf_shareddefs.h"
+
+#if defined( CLIENT_DLL )
+
+#include "iefx.h"
+#include "dlight.h"
+#include "clienteffectprecachesystem.h"
+#include "beamdraw.h"
+
+#define CWeaponCombatPlasmaRifle C_WeaponCombatPlasmaRifle
+#define CWeaponCombatPlasmaRifleHuman C_WeaponCombatPlasmaRifleHuman
+#define CWeaponCombatPlasmaRifleAlien C_WeaponCombatPlasmaRifleAlien
+
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#if defined( CLIENT_DLL )
+
+class CChargeBall;
+// Precache the effects
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheWeaponCombatPlasmaRifle )
+CLIENTEFFECT_MATERIAL( "sprites/chargeball_team1" )
+CLIENTEFFECT_MATERIAL( "sprites/chargeball_team2" )
+CLIENTEFFECT_REGISTER_END()
+
+#endif
+
+// Damage CVars
+ConVar weapon_combat_plasmarifle_damage( "weapon_combat_plasmarifle_damage","10", FCVAR_REPLICATED, "Plasma Rifle maximum damage" );
+ConVar weapon_combat_plasmarifle_range( "weapon_combat_plasmarifle_range","500", FCVAR_REPLICATED, "Plasma Rifle maximum range" );
+ConVar weapon_combat_plasmarifle_radius( "weapon_combat_plasmarifle_radius","90", FCVAR_REPLICATED, "Plasma Rifle explosion radius when charged" );
+ConVar weapon_combat_plasmarifle_ducking_mod( "weapon_combat_plasmarifle_ducking_mod", "0.6f", FCVAR_REPLICATED, "Plasma Rifle ducking speed modifier" );
+
+//-----------------------------------------------------------------------------
+// Purpose: Shared viersion of CWeaponCombatPlasmaRifle
+//-----------------------------------------------------------------------------
+class CWeaponCombatPlasmaRifle : public CWeaponCombatUsedWithShieldBase
+{
+ DECLARE_CLASS( CWeaponCombatPlasmaRifle, CWeaponCombatUsedWithShieldBase );
+public:
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+#if !defined( CLIENT_DLL )
+ DECLARE_DATADESC();
+#endif
+
+ CWeaponCombatPlasmaRifle( void ) {}
+
+ virtual void ItemPostFrame( void );
+ virtual void PrimaryAttack( void );
+ virtual float GetFireRate( void );
+ virtual void Spawn();
+ virtual bool Deploy( void );
+ virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
+ void ChargeThink( void );
+ virtual float GetDefaultAnimSpeed( void );
+
+ // All predicted weapons need to implement and return true
+ virtual bool IsPredicted( void ) const
+ {
+ return true;
+ }
+
+private:
+ CWeaponCombatPlasmaRifle( const CWeaponCombatPlasmaRifle & );
+public:
+
+#if defined( CLIENT_DLL )
+ virtual bool ShouldPredict( void )
+ {
+ if ( GetOwner() &&
+ GetOwner() == C_BasePlayer::GetLocalPlayer() )
+ return true;
+
+ return BaseClass::ShouldPredict();
+ }
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual int DrawModel( int flags );
+ virtual void ViewModelDrawn( CBaseViewModel *pBaseViewModel );
+ virtual void ClientThink( );
+ virtual bool IsTransparent( );
+private:
+ // Purpose: Draws the charging effect
+ void DrawChargingEffect( float flSize, CBaseAnimating *pAttachedEnt );
+ CMaterialReference m_hMaterial;
+
+#endif
+private:
+ CNetworkVar( float, m_flPower );
+ CNetworkVar( bool, m_bCharging );
+};
+
+//-----------------------------------------------------------------------------
+// Spawn weapon
+//-----------------------------------------------------------------------------
+void CWeaponCombatPlasmaRifle::Spawn()
+{
+ BaseClass::Spawn();
+ m_flPower = 1;
+ m_bCharging = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponCombatPlasmaRifle::ItemPostFrame( void )
+{
+ ChargeThink();
+
+ CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
+ if (!pOwner)
+ return;
+
+ if ( UsesClipsForAmmo1() )
+ {
+ CheckReload();
+ }
+
+ // Handle charge firing
+ if ( GetShieldState() == SS_DOWN && !m_bInReload )
+ {
+ if ( (pOwner->m_nButtons & IN_ATTACK ) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
+ {
+ if ( m_iClip1 > 0 )
+ {
+ // Fire the plasma shot
+ PrimaryAttack();
+ m_flPower = 1.0;
+ }
+ else
+ {
+ Reload();
+ }
+ }
+
+ // Reload button (or fire button when we're out of ammo)
+ if ( m_flNextPrimaryAttack <= gpGlobals->curtime )
+ {
+ if ( pOwner->m_nButtons & IN_RELOAD )
+ {
+ Reload();
+ }
+ else if ( !((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)) )
+ {
+ if ( !m_iClip1 && HasPrimaryAmmo() )
+ {
+ Reload();
+ }
+ }
+ }
+ }
+
+ // Prevent shield post frame if we're not ready to attack, or we're charging
+ AllowShieldPostFrame( m_flNextPrimaryAttack <= gpGlobals->curtime || m_bInReload );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponCombatPlasmaRifle::PrimaryAttack( void )
+{
+ CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
+ if (!pPlayer)
+ return;
+
+ WeaponSound(SINGLE);
+
+ // Fire the bullets
+ Vector vecSrc = pPlayer->Weapon_ShootPosition( );
+ Vector vecAiming;
+ pPlayer->EyeVectors( &vecAiming );
+
+ PlayAttackAnimation( GetPrimaryAttackActivity() );
+
+ // Shift it down a bit so the firer can see it
+ Vector right, forward;
+ AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, &forward, &right, NULL );
+ Vector vecStartSpot = vecSrc;
+
+ Vector gunOffset = Vector(0,0,-8) + right * 12 + forward * 16;
+
+ CPowerPlasmaProjectile *pPlasma = CPowerPlasmaProjectile::CreatePredicted( vecStartSpot, vecAiming, gunOffset, DMG_ENERGYBEAM, pPlayer );
+ if ( pPlasma )
+ {
+ pPlasma->SetDamage( m_flPower * weapon_combat_plasmarifle_damage.GetFloat() );
+ pPlasma->m_hOwner = pPlayer;
+ pPlasma->SetPower( m_flPower );
+ // Calculate range based upon charge power
+ float flRange = weapon_combat_plasmarifle_range.GetFloat() + RemapVal( m_flPower, 1.0, MAX_RIFLE_POWER, 0, weapon_combat_plasmarifle_range.GetFloat() * 0.75 );
+ pPlasma->SetMaxRange( flRange );
+ pPlasma->Activate();
+ }
+
+ // Go explosive if fully charged
+// if ( m_flPower >= MAX_RIFLE_POWER )
+// {
+// pPlasma->SetExplosive( weapon_combat_plasmarifle_radius.GetFloat() );
+// pPlasma->SetPlasmaType( PLASMATYPE_PLASMABALL_EXPLOSIVE );
+// }
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
+ m_iClip1 = m_iClip1 - 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CWeaponCombatPlasmaRifle::GetFireRate( void )
+{
+ float flFireRate = ( SequenceDuration() * 0.4 ) + SHARED_RANDOMFLOAT( 0.0, 0.035f );
+
+ // Get the player.
+ CBaseTFPlayer *pPlayer = ( CBaseTFPlayer* )GetOwner();
+ if ( pPlayer )
+ {
+ // Fire more rapidly when we are ducking.
+ if ( pPlayer->GetFlags() & FL_DUCKING )
+ {
+ flFireRate *= weapon_combat_plasmarifle_ducking_mod.GetFloat();
+ }
+ }
+
+ return flFireRate;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CWeaponCombatPlasmaRifle::Deploy( void )
+{
+ if ( BaseClass::Deploy() )
+ {
+ m_bCharging = true;
+ GainedNewTechnology(NULL);
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Our player just died
+//-----------------------------------------------------------------------------
+bool CWeaponCombatPlasmaRifle::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+ if ( BaseClass::Holster(pSwitchingTo) )
+ {
+ m_bCharging = false;
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Match the anim speed to the weapon speed while crouching
+//-----------------------------------------------------------------------------
+float CWeaponCombatPlasmaRifle::GetDefaultAnimSpeed( void )
+{
+ if ( GetOwner() && GetOwner()->IsPlayer() )
+ {
+ if ( GetOwner()->GetFlags() & FL_DUCKING )
+ return (1.0 + (1.0 - weapon_combat_plasmarifle_ducking_mod.GetFloat()) );
+ }
+
+ return 1.0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Charge up over time
+//-----------------------------------------------------------------------------
+void CWeaponCombatPlasmaRifle::ChargeThink( void )
+{
+ if ( !m_bCharging )
+ return;
+
+ if ( IsOwnerEMPed() )
+ {
+ m_flPower = 1;
+ }
+ else if ( m_iClip1 > 0 && m_flPower < MAX_RIFLE_POWER )
+ {
+ m_flPower = MIN( MAX_RIFLE_POWER, m_flPower + (((MAX_RIFLE_POWER-1.0) / RIFLE_CHARGE_TIME) * gpGlobals->frametime ) );
+ }
+}
+
+#if defined( CLIENT_DLL )
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponCombatPlasmaRifle::OnDataChanged( DataUpdateType_t updateType )
+{
+ SetPredictionEligible( true );
+
+ BaseClass::OnDataChanged( updateType );
+
+ if (updateType == DATA_UPDATE_CREATED)
+ {
+ if ( GetTeamNumber() == 1 )
+ m_hMaterial.Init( "sprites/chargeball_team1", TEXTURE_GROUP_CLIENT_EFFECTS );
+ else
+ m_hMaterial.Init( "sprites/chargeball_team2", TEXTURE_GROUP_CLIENT_EFFECTS );
+ }
+
+ 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 CWeaponCombatPlasmaRifle::ClientThink( )
+{
+ BaseClass::ClientThink();
+
+ if (!inv_demo.GetInt())
+ {
+ C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)GetOwner();
+ if ( !pPlayer || (pPlayer->GetHealth() <= 0) || !IsDormant() )
+ {
+ SetNextClientThink( CLIENT_THINK_NEVER );
+ return;
+ }
+
+ // 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 = 7;
+ dl->radius = 20 * m_flPower + 10;
+ dl->die = gpGlobals->curtime + 0.01;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the charging effect
+//-----------------------------------------------------------------------------
+void CWeaponCombatPlasmaRifle::DrawChargingEffect( float flSize, CBaseAnimating *pAttachedEnt )
+{
+ if (!pAttachedEnt)
+ return;
+
+ Vector vecMuzzleOrigin, vecBarrelOrigin;
+ QAngle angMuzzleAngles, angBarrelAngles;
+ int iMuzzle = pAttachedEnt->LookupAttachment( "muzzle" );
+ //int iBarrel = pAttachedEnt->LookupAttachment( "barrel" );
+
+ if ( pAttachedEnt->GetAttachment( iMuzzle, vecMuzzleOrigin, angMuzzleAngles ) )
+ {
+ // View model attachments are modified so you can place entities at the attachment
+ // point and when they are rendered (with a different FOV than the view model itself uses)
+ // they will render in the right spot when the view model is drawn.
+ //
+ // In this case though, we are rendering at the same time as the view model, so we want
+ // the attachment point before the correction has been applied.
+ pAttachedEnt->UncorrectViewModelAttachment( vecMuzzleOrigin );
+
+ // If I'm fully charged, put funky effects on the ball
+ materials->Bind( m_hMaterial, this );
+
+ if ( m_flPower >= MAX_RIFLE_POWER )
+ {
+ float frac = fmod( gpGlobals->curtime, 1.0 );
+ frac *= 2 * M_PI;
+ frac = sin( frac );
+ flSize += (frac * 2) - 1.5;
+ int colorFade = 190 + (int)( frac * 32.0f );
+
+ color32 color = { 0, 0, 0, 255 };
+ if ( GetTeamNumber() == 1 )
+ {
+ color.r = colorFade;
+ color.g = colorFade;
+ }
+ else
+ {
+ color.g = colorFade;
+ }
+ DrawSprite( vecMuzzleOrigin, flSize, flSize, color );
+ }
+ else
+ {
+ color32 color = { 255, 255, 255, 255 };
+ DrawSprite( vecMuzzleOrigin, flSize, flSize, color );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// We're transparent because we draw a transparent charging effect
+//-----------------------------------------------------------------------------
+bool CWeaponCombatPlasmaRifle::IsTransparent( )
+{
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the model
+//-----------------------------------------------------------------------------
+int CWeaponCombatPlasmaRifle::DrawModel( int flags )
+{
+ int retval = BaseClass::DrawModel( flags );
+ if (retval == 0)
+ return 0;
+
+ if (IsCarrierAlive())
+ {
+ // FIXME: Maybe do some client-side simulation on the size?
+ // It may get jerky otherwise
+
+ // Draw the charging effect
+ float flSize = 10 * m_flPower + 5;
+
+ DrawChargingEffect( flSize, this );
+ }
+ return retval;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the model
+//-----------------------------------------------------------------------------
+void CWeaponCombatPlasmaRifle::ViewModelDrawn( CBaseViewModel *pBaseViewModel )
+{
+ // Draw the charging effect
+ float flSize = 4 * m_flPower + 1;
+
+ if ( m_iClip1 > 0 )
+ {
+ DrawChargingEffect( flSize, pBaseViewModel );
+ }
+}
+#endif
+
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatPlasmaRifle, DT_WeaponCombatPlasmaRifle )
+
+BEGIN_NETWORK_TABLE( CWeaponCombatPlasmaRifle, DT_WeaponCombatPlasmaRifle )
+#if !defined( CLIENT_DLL )
+ SendPropFloat( SENDINFO( m_flPower ), 14, SPROP_ROUNDUP, 1.0f, MAX_RIFLE_POWER ),
+ SendPropInt( SENDINFO( m_bCharging ), 1, SPROP_UNSIGNED ),
+#else
+ RecvPropFloat( RECVINFO( m_flPower ) ),
+ RecvPropInt( RECVINFO( m_bCharging ) ),
+#endif
+END_NETWORK_TABLE()
+
+LINK_ENTITY_TO_CLASS( weapon_combat_plasmarifle_base, CWeaponCombatPlasmaRifle );
+
+BEGIN_PREDICTION_DATA( CWeaponCombatPlasmaRifle )
+
+ DEFINE_PRED_FIELD_TOL( m_flPower, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.05f ),
+ DEFINE_PRED_FIELD( m_bCharging, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+
+END_PREDICTION_DATA()
+
+#if !defined( CLIENT_DLL )
+
+BEGIN_DATADESC( CWeaponCombatPlasmaRifle )
+
+ // Function Pointers
+ DEFINE_FUNCTION( ChargeThink ),
+
+END_DATADESC()
+
+// PRECACHE_WEAPON_REGISTER(weapon_combat_plasmarifle_base);
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Need to do different art on client vs server
+//-----------------------------------------------------------------------------
+class CWeaponCombatPlasmaRifleHuman : public CWeaponCombatPlasmaRifle
+{
+ DECLARE_CLASS( CWeaponCombatPlasmaRifleHuman, CWeaponCombatPlasmaRifle );
+public:
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponCombatPlasmaRifleHuman( void ) {}
+
+private:
+ CWeaponCombatPlasmaRifleHuman( const CWeaponCombatPlasmaRifleHuman & );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Need to do different art on client vs server
+//-----------------------------------------------------------------------------
+class CWeaponCombatPlasmaRifleAlien : public CWeaponCombatPlasmaRifle
+{
+ DECLARE_CLASS( CWeaponCombatPlasmaRifleAlien, CWeaponCombatPlasmaRifle );
+public:
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ CWeaponCombatPlasmaRifleAlien( void ) {}
+
+private:
+ CWeaponCombatPlasmaRifleAlien( const CWeaponCombatPlasmaRifleAlien & );
+};
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatPlasmaRifleHuman, DT_WeaponCombatPlasmaRifleHuman )
+
+BEGIN_NETWORK_TABLE( CWeaponCombatPlasmaRifleHuman, DT_WeaponCombatPlasmaRifleHuman )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponCombatPlasmaRifleHuman )
+END_PREDICTION_DATA()
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatPlasmaRifleAlien, DT_WeaponCombatPlasmaRifleAlien )
+
+BEGIN_NETWORK_TABLE( CWeaponCombatPlasmaRifleAlien, DT_WeaponCombatPlasmaRifleAlien )
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponCombatPlasmaRifleAlien )
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( weapon_combat_plasmarifle, CWeaponCombatPlasmaRifleHuman );
+LINK_ENTITY_TO_CLASS( weapon_combat_plasmarifle_alien, CWeaponCombatPlasmaRifleAlien );
+
+PRECACHE_WEAPON_REGISTER(weapon_combat_plasmarifle);
+PRECACHE_WEAPON_REGISTER(weapon_combat_plasmarifle_alien);