diff options
Diffstat (limited to 'game/shared/tf2/weapon_combat_plasmarifle.cpp')
| -rw-r--r-- | game/shared/tf2/weapon_combat_plasmarifle.cpp | 559 |
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); |