//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWeaponBaseGun::PrimaryAttack( void ) { // Check for ammunition. if ( m_iClip1 <= 0 && UsesClipsForAmmo1() ) return; // Get the player owning the weapon. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() ); if ( !pPlayer ) return; if ( !CanAttack() ) return; if ( m_pWeaponInfo->GetWeaponData( TF_WEAPON_PRIMARY_MODE ).m_nBurstSize > 0 && m_iBurstSize == 0 ) { // Start the burst. m_iBurstSize = m_pWeaponInfo->GetWeaponData( TF_WEAPON_PRIMARY_MODE ).m_nBurstSize; } if ( m_iBurstSize > 0 ) { m_iBurstSize--; } CalcIsAttackCritical(); #ifndef CLIENT_DLL pPlayer->RemoveInvisibility(); pPlayer->RemoveDisguise(); // Minigun has custom handling if ( GetWeaponID() != TF_WEAPON_MINIGUN ) { pPlayer->SpeakWeaponFire(); } CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, IsCurrentAttackACrit() ); #endif // Set the weapon mode. m_iWeaponMode = TF_WEAPON_PRIMARY_MODE; SendWeaponAnim( ACT_VM_PRIMARYATTACK ); pPlayer->SetAnimation( PLAYER_ATTACK1 ); FireProjectile( pPlayer ); m_flLastFireTime = gpGlobals->curtime; // Set next attack times. float flFireDelay = m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_flTimeFireDelay; CALL_ATTRIB_HOOK_FLOAT( flFireDelay, mult_postfiredelay ); m_flNextPrimaryAttack = gpGlobals->curtime + flFireDelay; // Don't push out secondary attack, because our secondary fire // systems are all separate from primary fire (sniper zooming, demoman pipebomb detonating, etc) //m_flNextSecondaryAttack = gpGlobals->curtime + m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_flTimeFireDelay; // Set the idle animation times based on the sequence duration, so that we play full fire animations // that last longer than the refire rate may allow. SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() ); AbortReload(); }
void CWeaponShotgun::PrimaryAttack() { CSDKPlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; // don't fire underwater if (pPlayer->GetWaterLevel() == 3) { PlayEmptySound( ); m_flNextPrimaryAttack = gpGlobals->curtime + 0.15; return; } // Out of ammo? if ( m_iClip1 <= 0 ) { Reload(); if ( m_iClip1 == 0 ) { PlayEmptySound(); m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; } return; } SendWeaponAnim( ACT_VM_PRIMARYATTACK ); m_iClip1--; pPlayer->DoMuzzleFlash(); // player "shoot" animation pPlayer->SetAnimation( PLAYER_ATTACK1 ); // Dispatch the FX right away with full accuracy. FX_FireBullets( pPlayer->entindex(), pPlayer->Weapon_ShootPosition(), pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(), GetWeaponID(), Primary_Mode, CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server 0.0675 ); if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0) { // HEV suit - indicate out of ammo condition pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0); } if (m_iClip1 != 0) m_flPumpTime = gpGlobals->curtime + 0.5; m_flNextPrimaryAttack = gpGlobals->curtime + 0.875; m_flNextSecondaryAttack = gpGlobals->curtime + 0.875; if (m_iClip1 != 0) SetWeaponIdleTime( gpGlobals->curtime + 2.5 ); else SetWeaponIdleTime( gpGlobals->curtime + 0.875 ); m_fInSpecialReload = 0; // Update punch angles. QAngle angle = pPlayer->GetPunchAngle(); if ( pPlayer->GetFlags() & FL_ONGROUND ) { angle.x -= SharedRandomInt( "ShotgunPunchAngleGround", 4, 6 ); } else { angle.x -= SharedRandomInt( "ShotgunPunchAngleAir", 8, 11 ); } pPlayer->SetPunchAngle( angle ); }
bool CWeaponTFCBase::IsA( TFCWeaponID id ) const { return GetWeaponID() == id; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFlameThrower::PrimaryAttack() { // Are we capable of firing again? if ( m_flNextPrimaryAttack > gpGlobals->curtime ) return; // Get the player owning the weapon. CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); if ( !pOwner ) return; if ( !CanAttack() ) { #if defined ( CLIENT_DLL ) StopFlame(); #endif m_iWeaponState = FT_STATE_IDLE; return; } CalcIsAttackCritical(); // Because the muzzle is so long, it can stick through a wall if the player is right up against it. // Make sure the weapon can't fire in this condition by tracing a line between the eye point and the end of the muzzle. trace_t trace; Vector vecEye = pOwner->EyePosition(); Vector vecMuzzlePos = GetVisualMuzzlePos(); CTraceFilterIgnoreObjects traceFilter( this, COLLISION_GROUP_NONE ); UTIL_TraceLine( vecEye, vecMuzzlePos, MASK_SOLID, &traceFilter, &trace ); if ( trace.fraction < 1.0 && ( !trace.m_pEnt || trace.m_pEnt->m_takedamage == DAMAGE_NO ) ) { // there is something between the eye and the end of the muzzle, most likely a wall, don't fire, and stop firing if we already are if ( m_iWeaponState > FT_STATE_IDLE ) { #if defined ( CLIENT_DLL ) StopFlame(); #endif m_iWeaponState = FT_STATE_IDLE; } return; } switch ( m_iWeaponState ) { case FT_STATE_IDLE: case FT_STATE_AIRBLASTING: { // Just started, play PRE and start looping view model anim pOwner->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRE ); SendWeaponAnim( ACT_VM_PRIMARYATTACK ); m_flStartFiringTime = gpGlobals->curtime + 0.16; // 5 frames at 30 fps m_iWeaponState = FT_STATE_STARTFIRING; } break; case FT_STATE_STARTFIRING: { // if some time has elapsed, start playing the looping third person anim if ( gpGlobals->curtime > m_flStartFiringTime ) { m_iWeaponState = FT_STATE_FIRING; m_flNextPrimaryAttackAnim = gpGlobals->curtime; } } break; case FT_STATE_FIRING: { if ( gpGlobals->curtime >= m_flNextPrimaryAttackAnim ) { pOwner->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY ); m_flNextPrimaryAttackAnim = gpGlobals->curtime + 1.4; // fewer than 45 frames! } } break; default: break; } #ifdef CLIENT_DLL // Restart our particle effect if we've transitioned across water boundaries if ( m_iParticleWaterLevel != -1 && pOwner->GetWaterLevel() != m_iParticleWaterLevel ) { if ( m_iParticleWaterLevel == WL_Eyes || pOwner->GetWaterLevel() == WL_Eyes ) { RestartParticleEffect(); } } #endif #ifdef CLIENT_DLL // Handle the flamethrower light if (tf2c_muzzlelight.GetBool()) { dlight_t *dl = effects->CL_AllocDlight(LIGHT_INDEX_MUZZLEFLASH + index); dl->origin = vecMuzzlePos; dl->color.r = 255; dl->color.g = 100; dl->color.b = 10; dl->die = gpGlobals->curtime + 0.01f; dl->radius = 240.f; dl->decay = 512.0f; dl->style = 5; } #endif #if !defined (CLIENT_DLL) // Let the player remember the usercmd he fired a weapon on. Assists in making decisions about lag compensation. pOwner->NoteWeaponFired(); pOwner->SpeakWeaponFire(); CTF_GameStats.Event_PlayerFiredWeapon( pOwner, m_bCritFire ); // Move other players back to history positions based on local player's lag lagcompensation->StartLagCompensation( pOwner, pOwner->GetCurrentCommand() ); #endif float flFiringInterval = m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_flTimeFireDelay; CALL_ATTRIB_HOOK_FLOAT( flFiringInterval, mult_postfiredelay ); // Don't attack if we're underwater if ( pOwner->GetWaterLevel() != WL_Eyes ) { // Find eligible entities in a cone in front of us. Vector vOrigin = pOwner->Weapon_ShootPosition(); Vector vForward, vRight, vUp; QAngle vAngles = pOwner->EyeAngles() + pOwner->GetPunchAngle(); AngleVectors( vAngles, &vForward, &vRight, &vUp ); #define NUM_TEST_VECTORS 30 #ifdef CLIENT_DLL bool bWasCritical = m_bCritFire; #endif // Burn & Ignite 'em int iDmgType = g_aWeaponDamageTypes[ GetWeaponID() ]; m_bCritFire = IsCurrentAttackACrit(); if ( m_bCritFire ) { iDmgType |= DMG_CRITICAL; } #ifdef CLIENT_DLL if ( bWasCritical != m_bCritFire ) { RestartParticleEffect(); } #endif #ifdef GAME_DLL // create the flame entity int iDamagePerSec = m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_nDamage; float flDamage = (float)iDamagePerSec * flFiringInterval; CALL_ATTRIB_HOOK_FLOAT( flDamage, mult_dmg ); CTFFlameEntity::Create( GetFlameOriginPos(), pOwner->EyeAngles(), this, iDmgType, flDamage ); #endif } #ifdef GAME_DLL // Figure how much ammo we're using per shot and add it to our remainder to subtract. (We may be using less than 1.0 ammo units // per frame, depending on how constants are tuned, so keep an accumulator so we can expend fractional amounts of ammo per shot.) // Note we do this only on server and network it to client. If we predict it on client, it can get slightly out of sync w/server // and cause ammo pickup indicators to appear float flAmmoPerSecond = TF_FLAMETHROWER_AMMO_PER_SECOND_PRIMARY_ATTACK; CALL_ATTRIB_HOOK_FLOAT( flAmmoPerSecond, mult_flame_ammopersec ); m_flAmmoUseRemainder += flAmmoPerSecond * flFiringInterval; // take the integer portion of the ammo use accumulator and subtract it from player's ammo count; any fractional amount of ammo use // remains and will get used in the next shot int iAmmoToSubtract = (int) m_flAmmoUseRemainder; if ( iAmmoToSubtract > 0 ) { pOwner->RemoveAmmo( iAmmoToSubtract, m_iPrimaryAmmoType ); m_flAmmoUseRemainder -= iAmmoToSubtract; // round to 2 digits of precision m_flAmmoUseRemainder = (float) ( (int) (m_flAmmoUseRemainder * 100) ) / 100.0f; } #endif m_flNextPrimaryAttack = gpGlobals->curtime + flFiringInterval; m_flTimeWeaponIdle = gpGlobals->curtime + flFiringInterval; #if !defined (CLIENT_DLL) lagcompensation->FinishLagCompensation( pOwner ); #endif }
void CWeaponUSP::USPFire( float flSpread ) { CCSPlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; float flCycleTime = GetCSWpnData().m_flCycleTime; pPlayer->m_iShotsFired++; if (pPlayer->m_iShotsFired > 1) return; // Mark the time of this shot and determine the accuracy modifier based on the last shot fired... m_flAccuracy -= (0.275)*(0.3 - (gpGlobals->curtime - m_flLastFire)); if (m_flAccuracy > 0.92) m_flAccuracy = 0.92; else if (m_flAccuracy < 0.6) m_flAccuracy = 0.6; m_flLastFire = gpGlobals->curtime; if (m_iClip1 <= 0) { if (m_bFireOnEmpty) { PlayEmptySound(); m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; } return; } m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + flCycleTime; m_iClip1--; SendWeaponAnim( ACT_VM_PRIMARYATTACK ); // player "shoot" animation pPlayer->SetAnimation( PLAYER_ATTACK1 ); if ( !m_bSilencerOn ) { pPlayer->DoMuzzleFlash(); } FX_FireBullets( pPlayer->entindex(), pPlayer->Weapon_ShootPosition(), pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(), GetWeaponID(), m_bSilencerOn?Secondary_Mode:Primary_Mode, CBaseEntity::GetPredictionRandomSeed() & 255, flSpread ); if (!m_iClip1 && pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0) { // HEV suit - indicate out of ammo condition pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0); } SetWeaponIdleTime( gpGlobals->curtime + 2 ); QAngle angle = pPlayer->GetPunchAngle(); angle.x -= 2; pPlayer->SetPunchAngle( angle ); }