📄 weapon_repairgun.cpp
字号:
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Overloaded to handle the hold-down healing
//-----------------------------------------------------------------------------
void CWeaponRepairGun::ItemPostFrame( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return;
#if !defined( CLIENT_DLL )
if ( AppliesModifier() )
{
m_DamageModifier.SetModifier( weapon_repairgun_damage_modifier.GetFloat() );
}
#endif
// Try to start healing
m_bAttacking = false;
if ( (pOwner->m_nButtons & IN_ATTACK) && GetShieldState() == SS_DOWN )
{
PrimaryAttack();
m_bAttacking = true;
}
else if ( GetCurHealingTarget() )
{
// Detach from the player if they release the attack button.
RemoveHealingTarget();
}
// Prevent shield post frame if we're not ready to attack, or we're healing
AllowShieldPostFrame( !m_bAttacking );
WeaponIdle();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponRepairGun::RemoveHealingTarget()
{
// Stop the welding animation
if ( m_bHealing )
{
SendWeaponAnim( ACT_FIRE_END );
}
m_hHealingTarget = NULL;
#if !defined( CLIENT_DLL )
m_DamageModifier.RemoveModifier();
#endif
m_bHealing = false;
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( pOwner )
{
pOwner->SetIDEnt( NULL );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWeaponRepairGun::ComputeEMPFireState( void )
{
if ( IsOwnerEMPed() )
{
// If we've just been EMPed, remove the heal target
if ( GetCurHealingTarget() )
{
RemoveHealingTarget();
}
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Attempt to heal any player within range of the medikit
//-----------------------------------------------------------------------------
void CWeaponRepairGun::PrimaryAttack( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return;
// Can't fire if we've been EMPed.
if ( !ComputeEMPFireState() )
return;
#if !defined( CLIENT_DLL )
// Find a Player to buff with hitscan
CBaseEntity *pCurHealing = GetCurHealingTarget();
CBaseEntity *pTarget = GetTargetToHeal( pCurHealing );
if ( pTarget )
{
// Start the welding animation
if ( !m_bHealing )
{
SendWeaponAnim( ACT_FIRE_START );
}
// Tell the client who we're trying to heal.
m_bHealing = true;
m_hHealingTarget = pTarget;
// Repairgun needs to EMP grenades, heal everything else
#ifdef REPAIR_GUN_DISABLES_GRENADES
CBaseEMPableGrenade *pGrenade = dynamic_cast<CBaseEMPableGrenade*>(pTarget);
if ( pGrenade )
{
pTarget->TakeEMPDamage( 1.0 );
}
else
#endif
{
// Can't bring things back from the dead
if ( pTarget->IsAlive() )
{
float flBoostAmount = GetHealRate() * gpGlobals->frametime;
// If it's an object, and it's constructing, use the construction heal rate
if ( pTarget->Classify() == CLASS_MILITARY )
{
CBaseObject *pObject = dynamic_cast<CBaseObject*>(pTarget);
if ( pObject && pObject->IsBuilding() )
{
flBoostAmount = weapon_repairgun_construction_rate.GetFloat() * gpGlobals->frametime;
}
if ( pObject && pObject->IsDying() )
{
flBoostAmount = 0;
}
}
// If we're not succeeding, remove the damage modifier
if ( !pTarget->AttemptToPowerup( POWERUP_BOOST, 1.0, flBoostAmount, pOwner, AppliesModifier() ? &m_DamageModifier : NULL ) )
{
m_DamageModifier.RemoveModifier();
}
// Force the player's ID target to the heal target
pOwner->SetIDEnt( pTarget );
}
}
}
else
{
RemoveHealingTarget();
}
#endif
CheckRemoveDisguise();
}
void CWeaponRepairGun::PlayAttackAnimation( int activity )
{
SendWeaponAnim( activity );
}
//-----------------------------------------------------------------------------
// Purpose: Idle tests to see if we're facing a valid target for the medikit
// If so, move into the "heal-able" animation.
// Otherwise, move into the "not-heal-able" animation.
//-----------------------------------------------------------------------------
void CWeaponRepairGun::WeaponIdle( void )
{
if ( HasWeaponIdleTimeElapsed() )
{
// Loop the welding animation
if ( m_bHealing )
{
SendWeaponAnim( ACT_FIRE_LOOP );
}
else
{
// select an idle animation
SendWeaponAnim( ACT_VM_IDLE );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: The player holding this weapon has just gained new technology.
// Check to see if it affects the medikit
//-----------------------------------------------------------------------------
void CWeaponRepairGun::GainedNewTechnology( CBaseTechnology *pTechnology )
{
}
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponRepairGun::StopRepairSound( bool bStopHealingSound, bool bStopNoTargetSound )
{
if ( bStopHealingSound )
{
StopSound( "WeaponRepairGun.Healing" );
}
if ( bStopNoTargetSound )
{
StopSound( "WeaponRepairGun.NoTarget" );
}
}
void C_WeaponRepairGun::NotifyShouldTransmit( ShouldTransmitState_t state )
{
// Stop emitting particles if we're going dormant.
if ( state == SHOULDTRANSMIT_END )
{
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_NEVER );
}
BaseClass::NotifyShouldTransmit( state );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_WeaponRepairGun::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
m_pEmitter = CSimpleEmitter::Create( "C_WeaponRepairGun" );
m_hParticleMaterial = m_pEmitter->GetPMaterial( "sprites/chargeball" );
}
// Think?
if ( m_bHealing && m_hHealingTarget.Get())
{
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS );
}
else
{
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_NEVER );
m_bPlayingSound = false;
StopRepairSound( true, false );
// Are they holding the attack button but not healing anyone? Give feedback.
if ( IsActiveByLocalPlayer() && GetOwner() && GetOwner()->IsAlive() && m_bAttacking && GetOwner() == C_BasePlayer::GetLocalPlayer() )
{
if ( gpGlobals->curtime >= m_flNextBuzzTime )
{
CLocalPlayerFilter filter;
EmitSound( filter, entindex(), "WeaponRepairGun.NoTarget" );
m_flNextBuzzTime = gpGlobals->curtime + 0.5f; // only buzz every so often.
}
}
else
{
StopRepairSound( false, true ); // Stop the "no target" sound.
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_WeaponRepairGun::ClientThink()
{
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer )
return;
if ( m_hHealingTarget == NULL )
{
return;
}
// Don't show it while the player is dead. Ideally, we'd respond to m_bHealing in OnDataChanged,
// but it stops sending the weapon when it's holstered, and it gets holstered when the player dies.
C_BasePlayer *pFiringPlayer = dynamic_cast< C_BasePlayer* >( GetOwner() );
if ( !pFiringPlayer || pFiringPlayer->IsPlayerDead() )
{
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_NEVER );
m_bPlayingSound = false;
StopRepairSound();
return;
}
if ( !m_bPlayingSound )
{
m_bPlayingSound = true;
CLocalPlayerFilter filter;
EmitSound( filter, entindex(), "WeaponRepairGun.Healing" );
}
Vector points[NUM_REPAIRGUN_PATH_POINTS];
// First generate a sequence of points so we can parameterize the (curvy) path from the
// tip of the gun to the target.
Vector vForward, vOrigin;
QAngle vAngles;
GetShootPosition( vOrigin, vAngles );
AngleVectors( vAngles, &vForward );
Vector vecTargetOrg = m_hHealingTarget->WorldSpaceCenter();
Vector vDirTo = vecTargetOrg - vOrigin;
float flDistanceTo = vDirTo.Length();
vDirTo /= flDistanceTo;
float flBendDist = flDistanceTo * 3;
const Vector A = vOrigin - vForward * flBendDist;
const Vector &B = vOrigin;
const Vector &C = vecTargetOrg;
const Vector D = vecTargetOrg - vForward * flBendDist;
for ( int i=0; i < NUM_REPAIRGUN_PATH_POINTS; i++ )
{
Catmull_Rom_Spline( A, B, C, D, (float)i / (NUM_REPAIRGUN_PATH_POINTS-1), points[i] );
}
// Add random short-lived particles from the gun tip to the target.
m_pEmitter->SetSortOrigin( (vecTargetOrg + pPlayer->GetAbsOrigin()) * 0.5f );
float flCur = gpGlobals->frametime;
while ( m_PathParticleEvent.NextEvent( flCur ) )
{
float t = RandomFloat( 0, 1 );
int iPrev = (int)( t * (NUM_REPAIRGUN_PATH_POINTS - 1.001) );
float tPrev = (float)iPrev / (NUM_REPAIRGUN_PATH_POINTS - 1);
float tNext = (float)(iPrev+1) / (NUM_REPAIRGUN_PATH_POINTS - 1);
Assert( tNext <= NUM_REPAIRGUN_PATH_POINTS-1 );
Vector vPos;
VectorLerp( points[iPrev], points[iPrev+1], (t-tPrev) / (tNext - tPrev), vPos );
vPos += RandomVector( -3, 3 );
SimpleParticle *pParticle = m_pEmitter->AddSimpleParticle( m_hParticleMaterial, vPos );
if ( pParticle )
{
// Move the points along the path.
pParticle->m_vecVelocity = points[iPrev+1] - points[iPrev];
VectorNormalize( pParticle->m_vecVelocity );
pParticle->m_vecVelocity *= PARTICLE_PATH_VEL;
pParticle->m_flRoll = 0;
pParticle->m_flRollDelta = 0;
pParticle->m_flDieTime = 0.2f;
pParticle->m_flLifetime = 0;
pParticle->m_uchColor[1] = 200;
pParticle->m_uchColor[0] = pParticle->m_uchColor[2] = RandomInt( 0, 128 );
pParticle->m_uchStartAlpha = 255;
pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = 5;
pParticle->m_uchEndSize = 3;
pParticle->m_iFlags = 0;
}
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -