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.
559 lines
16 KiB
559 lines
16 KiB
//========= 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);
|
|
|