//----------------------------------------------------------------------------- // Purpose: Idle updates the position of the build placement model //----------------------------------------------------------------------------- void CWeaponBuilder::WeaponIdle( void ) { CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if ( !pOwner ) return; // If we're in placement mode, update the placement model switch( m_iBuildState ) { case BS_PLACING: case BS_PLACING_INVALID: { if ( UpdatePlacement() ) { SetCurrentState( BS_PLACING ); } else { SetCurrentState( BS_PLACING_INVALID ); } } break; default: break; } if ( HasWeaponIdleTimeElapsed() ) { SendWeaponAnim( ACT_VM_IDLE ); } }
//----------------------------------------------------------------------------- // Purpose: Move the placement model to the current position. Return false if it's an invalid position //----------------------------------------------------------------------------- bool CWeaponBuilder::UpdatePlacement( void ) { if ( !m_hObjectBeingBuilt ) return false; return m_hObjectBeingBuilt->UpdatePlacement( ToBaseTFPlayer(GetOwner()) ); }
//----------------------------------------------------------------------------- // New technologies: //----------------------------------------------------------------------------- void CWeaponCombat_ChargeablePlasma::GainedNewTechnology( CBaseTechnology *pTechnology ) { BaseClass::GainedNewTechnology( pTechnology ); CBaseTFPlayer *pPlayer = ToBaseTFPlayer( (CBaseEntity*)GetOwner() ); if ( pPlayer ) { // Charge-up mode? if ( pPlayer->HasNamedTechnology( "com_comboshield_charge" ) ) { m_bHasCharge = true; } else { m_bHasCharge = false; } // Burst shot mode? if ( pPlayer->HasNamedTechnology( "com_comboshield_tripleshot" ) ) { m_bHasBurstShot = true; } else { m_bHasBurstShot = false; } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponBuilder::ItemPostFrame( void ) { CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if ( !pOwner ) return; // Ignore input while the player's building anything if ( pOwner->IsBuilding() ) return; // Switch away if I'm not in placement mode if ( m_iBuildState != BS_PLACING && m_iBuildState != BS_PLACING_INVALID ) { pOwner->SwitchToNextBestWeapon( NULL ); return; } if (( pOwner->m_nButtons & IN_ATTACK ) && (m_flNextPrimaryAttack <= gpGlobals->curtime) ) { PrimaryAttack(); } // Allow shield post frame AllowShieldPostFrame( true ); WeaponIdle(); }
//----------------------------------------------------------------------------- // Purpose: The player holding this weapon has just gained new technology. // Check to see if it affects the medikit //----------------------------------------------------------------------------- void CWeaponBuilder::GainedNewTechnology( CBaseTechnology *pTechnology ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( pPlayer ) { // Force a recalculation of the state for this object SetCurrentObject( m_iCurrentObject ); } }
//----------------------------------------------------------------------------- // Purpose: Handle deploying, undeploying, firing, etc. // TODO: Add a deploy to the firing! Currently no reloading! //----------------------------------------------------------------------------- void CWeaponRocketLauncher::ItemPostFrame( void ) { // Get the player. CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( !pPlayer ) return; if ( UsesClipsForAmmo1() ) { CheckReload(); } #if !defined( CLIENT_DLL ) if ( !HasPrimaryAmmo() && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) ) { pPlayer->SwitchToNextBestWeapon( NULL ); } #endif // Handle Firing if ( GetShieldState() == SS_DOWN && !m_bInReload ) { // Attempting to fire. if ( ( pPlayer->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) ) { if ( m_iClip1 > 0 ) { PrimaryAttack(); } else { Reload(); } } // Reload button (or fire button when we're out of ammo) if ( m_flNextPrimaryAttack <= gpGlobals->curtime ) { if ( pPlayer->m_nButtons & IN_RELOAD ) { Reload(); } else if ( !((pPlayer->m_nButtons & IN_ATTACK) || (pPlayer->m_nButtons & IN_ATTACK2) || (pPlayer->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: Reset all the player's resource banks //----------------------------------------------------------------------------- void CInfoInputResetBanks::InputResetAll( inputdata_t &inputdata ) { for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) ); if ( pPlayer ) { ResetPlayersBank( pPlayer ); } } }
//----------------------------------------------------------------------------- // Purpose: Play sound to all players //----------------------------------------------------------------------------- void CInfoInputPlaySound::InputPlaySoundToAll( inputdata_t &inputdata ) { for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) ); if ( pPlayer ) { PlaySoundToPlayer( pPlayer ); } } }
//----------------------------------------------------------------------------- // Purpose: Player holding this weapon has aborted the build of an object //----------------------------------------------------------------------------- void CWeaponBuilder::StoppedBuilding( int iObjectType ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( pPlayer ) { // Force a recalculation of the state for this object SetCurrentObject( m_iCurrentObject ); SetCurrentState( BS_IDLE ); WeaponSound( SPECIAL2 ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponBuilder::UpdateOnRemove( void ) { // Tell the player he's lost his build weapon CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if ( pOwner && pOwner->GetWeaponBuilder() == this ) { pOwner->SetWeaponBuilder( NULL ); } // Chain at end to mimic destructor unwind order BaseClass::UpdateOnRemove(); }
//----------------------------------------------------------------------------- // Purpose: Run through all the Bots in the game and let them think. //----------------------------------------------------------------------------- void Bot_RunAll( void ) { for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex( i ) ); if ( pPlayer && (pPlayer->GetFlags() & FL_FAKECLIENT) ) { Bot_Think( pPlayer ); } } }
//----------------------------------------------------------------------------- // Purpose: Bash enemies in front of me with my shield //----------------------------------------------------------------------------- void CWeaponCombatShield::ShieldBash( void ) { #if 0 // ROBIN: Disabled shield bash return; // Get any players in front of me CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if ( !pOwner ) return; // Get the target point and location Vector vecAiming; Vector vecSrc = pOwner->Weapon_ShootPosition( pOwner->GetOrigin() ); pOwner->EyeVectors( &vecAiming ); // Find a player in range of this player, and make sure they're healable trace_t tr; Vector vecEnd = vecSrc + (vecAiming * SHIELD_BASH_RANGE); UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT, pOwner->edict(), COLLISION_GROUP_NONE, &tr); if (tr.fraction != 1.0) { CBaseEntity *pEntity = CBaseEntity::Instance(tr.u.ent); if ( pEntity ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( pEntity ); if ( pPlayer && (pPlayer != pOwner) ) { // Target needs to be on the eneny team if ( pPlayer->IsAlive() && !pPlayer->InSameTeam( pOwner ) ) { // Ok, we have an enemy player pPlayer->TakeShieldBash( pOwner ); } } } } #endif }
//----------------------------------------------------------------------------- // Purpose: The player holding this weapon has just finished building an object //----------------------------------------------------------------------------- void CWeaponBuilder::FinishedObject( void ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( pPlayer ) { // We're no longer building anything... m_hObjectBeingBuilt = NULL; // Force a recalculation of the state for this object SetCurrentObject( m_iCurrentObject ); SetCurrentState( BS_IDLE ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponCombatLaserRifle::ItemPostFrame( void ) { CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if (!pOwner) return; if ( UsesClipsForAmmo1() ) { CheckReload(); } RecalculateAccuracy(); // Handle 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(); } 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: Check to see if the shield state should change //----------------------------------------------------------------------------- void CWeaponCombatShield::UpdateShieldState( void ) { CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if ( !pOwner ) return; // Check to see if I should move out of the current state switch ( m_iShieldState ) { default: case SS_DOWN: case SS_UP: break; case SS_RAISING: if ( gpGlobals->curtime > m_flShieldRaisedTime ) { SetShieldState( SS_UP ); } break; case SS_LOWERING: if ( gpGlobals->curtime > m_flShieldLoweredTime ) { SetShieldState( SS_DOWN ); } break; case SS_PARRYING: if ( gpGlobals->curtime > m_flShieldParryEndTime ) { SetShieldState( SS_PARRYING_FINISH_SWING ); } break; case SS_PARRYING_FINISH_SWING: if ( gpGlobals->curtime > m_flShieldParrySwingEndTime ) { SetShieldState( SS_UNAVAILABLE ); } break; case SS_UNAVAILABLE: if ( gpGlobals->curtime > m_flShieldUnavailableEndTime ) { SetShieldState( SS_DOWN ); } break; }; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponMortar::MortarDestroyed( void ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( pPlayer ) { ClientPrint( pPlayer, HUD_PRINTCENTER, "\n\n\n\n\n\n\n\n\n\nMortar Destroyed!" ); } if ( pPlayer && pPlayer->GetActiveWeapon() == this ) { SendWeaponAnim( ACT_SLAM_TRIPMINE_DRAW ); } MortarObjectRemoved(); }
//----------------------------------------------------------------------------- // Purpose: Records that a player has left the zone, and updates it's state // according, maybe starting to change team. // Input : *pOther - the entity that left the zone //----------------------------------------------------------------------------- void CControlZone::EndTouch( CBaseEntity *pOther ) { CBaseTFPlayer *pl = ToBaseTFPlayer( pOther ); if ( !pl ) return; CHandle< CBaseTFPlayer > hHandle; hHandle = pl; m_ZonePlayerList.FindAndRemove( hHandle ); ReevaluateControllingTeam(); // Unset this player's current zone if it's this one if ( pl->GetCurrentZone() == this ) pl->SetCurrentZone( NULL ); }
//----------------------------------------------------------------------------- // Purpose: Records that a player has entered the zone, and updates it's state // according, maybe starting to change team. // Input : *pOther - the entity that left the zone //----------------------------------------------------------------------------- void CControlZone::StartTouch( CBaseEntity *pOther ) { CBaseTFPlayer *pl = ToBaseTFPlayer( pOther ); if ( !pl ) return; CHandle< CBaseTFPlayer > hHandle; hHandle = pl; m_ZonePlayerList.AddToTail( hHandle ); ReevaluateControllingTeam(); // Set this player's current zone to this zone pl->SetCurrentZone( this ); }
//----------------------------------------------------------------------------- // Purpose: Start placing the object //----------------------------------------------------------------------------- void CWeaponBuilder::StartPlacement( void ) { StopPlacement(); // Create the slab m_hObjectBeingBuilt = (CBaseObject*)CreateEntityByName( GetObjectInfo( m_iCurrentObject )->m_pClassName ); if ( m_hObjectBeingBuilt ) { m_hObjectBeingBuilt->Spawn(); m_hObjectBeingBuilt->StartPlacement( ToBaseTFPlayer( GetOwner() ) ); UpdatePlacement(); // Stomp this here in the same frame we make the object, so prevent clientside warnings that it's under attack m_hObjectBeingBuilt->m_iHealth = OBJECT_CONSTRUCTION_STARTINGHEALTH; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CWeaponCombatShield::Holster( CBaseCombatWeapon *pSwitchingTo ) { CBaseTFPlayer *player = ToBaseTFPlayer( GetOwner() ); if ( player ) { player->SetBlocking( false ); player->SetParrying( false ); if ( m_iShieldState != SS_DOWN && m_iShieldState != SS_UNAVAILABLE ) { SetShieldState( SS_LOWERING ); } } return true; }
//----------------------------------------------------------------------------- // Purpose: Set the deployed mortar's firing round //----------------------------------------------------------------------------- void CWeaponMortar::SetRoundType( int iRoundType ) { if ( m_hDeployedMortar == NULL ) return; // Make sure we've got the technology for this round type if ( MortarAmmoTechs[ iRoundType ] && MortarAmmoTechs[ iRoundType ][0] ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( !pPlayer ) return; // Does the player have the technology? if ( pPlayer->HasNamedTechnology( MortarAmmoTechs[ iRoundType ] ) == false ) return; } m_hDeployedMortar->m_iRoundType = iRoundType; }
//----------------------------------------------------------------------------- // Purpose: The player holding this weapon has just gained new technology. //----------------------------------------------------------------------------- void CWeaponCombatShield::GainedNewTechnology( CBaseTechnology *pTechnology ) { BaseClass::GainedNewTechnology( pTechnology ); CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( pPlayer ) { // Has a parry? if ( pPlayer->HasNamedTechnology( "com_comboshield_parry" ) ) { m_bHasShieldParry = true; } else { m_bHasShieldParry = false; } } }
//----------------------------------------------------------------------------- // Purpose: The player holding this weapon has just gained new technology. // Check to see if it affects the mortar //----------------------------------------------------------------------------- void CWeaponMortar::GainedNewTechnology( CBaseTechnology *pTechnology ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( pPlayer ) { // Range upgraded? if ( pPlayer->HasNamedTechnology("mortar_range") ) m_bRangeUpgraded = true; else m_bRangeUpgraded = false; // Accuracy upgraded? if ( pPlayer->HasNamedTechnology("mortar_accuracy") ) m_bAccuracyUpgraded = true; else m_bAccuracyUpgraded = false; } }
//----------------------------------------------------------------------------- // Purpose: Set the builder to the specified object //----------------------------------------------------------------------------- void CWeaponBuilder::SetCurrentObject( int iObject ) { // Fixup for invalid objects if (iObject < 0) iObject = BUILDER_INVALID_OBJECT; CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if ( !pOwner ) return; int i; // If -1 was passed in, set to our first available object if ( iObject == BUILDER_INVALID_OBJECT ) { for ( i = 0; i < OBJ_LAST; i++ ) { if ( m_bObjectValidity[i] ) { iObject = i; break; } } } // Recalculate the buildability of each object (for propagation to the client) for ( i=0; i < m_bObjectBuildability.Count(); i++ ) m_bObjectBuildability.Set( i, 0 ); for ( i = 0; i < OBJ_LAST; i++ ) { if ( m_bObjectValidity[i] && pOwner->CanBuild(i) == CB_CAN_BUILD ) { m_bObjectBuildability.Set( i, true ); } } m_iCurrentObject = iObject; m_iCurrentObjectState = pOwner->CanBuild( m_iCurrentObject ); m_flStartTime = 0; m_flTotalTime = 0; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHarpoon::ImpaleTarget( CBaseEntity *pOther ) { // Impale! EmitSound( "Harpoon.Impale" ); // Calculate our impale offset m_vecOffset = (pOther->GetAbsOrigin() - GetAbsOrigin()); m_angOffset = (pOther->GetAbsAngles() - GetAbsAngles()); FollowEntity( pOther ); // Do some damage to the target if ( pOther->m_takedamage ) { CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwnerEntity() ); if ( !pOwner ) return; pOther->TakeDamage( CTakeDamageInfo( this, pOwner, weapon_harpoon_damage.GetFloat(), DMG_GENERIC ) ); } }
//----------------------------------------------------------------------------- // Purpose: Attempt to block the incoming attack, and return the damage it // should do after the block, if any. //----------------------------------------------------------------------------- float CWeaponCombatShield::AttemptToBlock( float flDamage ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( !pPlayer || !weapon_combat_shield_factor.GetFloat() ) return 0; // Block as much of the damage as we can float flPowerNeeded = flDamage * weapon_combat_shield_factor.GetFloat(); flPowerNeeded = RemapVal( flPowerNeeded, 0, weapon_combat_shield_health.GetFloat(), 0, 1 ); float flPowerUsed = min( flPowerNeeded, GetShieldHealth() ); #ifndef CLIENT_DLL RemoveShieldHealth( flPowerUsed ); // Start recharging shortly after taking damage SetThink( ShieldRechargeThink ); SetNextThink( gpGlobals->curtime + weapon_combat_shield_rechargetime.GetFloat() ); #endif // Failed to block it all? if ( flPowerUsed < flPowerNeeded ) { #ifndef CLIENT_DLL // Force the shield to drop if it's up if ( GetShieldState() == SS_UP ) { // Play sound & anim SendWeaponAnim( ACT_VM_HAULBACK ); WeaponSound( SPECIAL2 ); SetShieldState( SS_LOWERING ); } #endif return ( flDamage - (flPowerUsed * (1.0 / weapon_combat_shield_factor.GetFloat())) ); } return 0; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponMortar::PrimaryAttack( void ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() ); if ( !pPlayer ) return; // Can't attack if taking EMP damage if ( !ComputeEMPFireState() ) return; if ( IsOwnerEMPed() ) return; if ( m_hDeployedMortar == NULL ) return; if ( m_hDeployedMortar->FireMortar( m_flFiringPower, m_flFiringAccuracy, m_bRangeUpgraded, m_bAccuracyUpgraded ) ) { WeaponSound( SINGLE ); } m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; CheckRemoveDisguise(); }
//----------------------------------------------------------------------------- // Purpose: I've been bashed by another player's shield //----------------------------------------------------------------------------- bool CWeaponCombatShield::TakeShieldBash( CBaseTFPlayer *pBasher ) { CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if ( !pOwner ) return false; // If I'm blocking, drop my block and prevent me from doing anything if ( GetShieldState() == SS_UP || GetShieldState() == SS_RAISING || GetShieldState() == SS_LOWERING ) { // Make the shield unavailable SetShieldState( SS_UNAVAILABLE ); SendWeaponAnim( ACT_VM_HITCENTER ); m_flShieldUnavailableEndTime = gpGlobals->curtime + 2.0; // Play a sound EmitSound( "WeaponCombatShield.TakeBash" ); return true; } return false; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponLaserRifle::PrimaryAttack( void ) { CBaseTFPlayer *pPlayer = ToBaseTFPlayer( m_hOwner ); if ( !pPlayer ) return; if ( !ComputeEMPFireState() ) return; WeaponSound(SINGLE); PlayAttackAnimation( GetPrimaryAttackActivity() ); pPlayer->m_fEffects |= EF_MUZZLEFLASH; // Fire the beam: BLOW OFF AUTOAIM Vector vecSrc = pPlayer->Weapon_ShootPosition( pPlayer->GetOrigin() ); Vector vecAiming, right, up; pPlayer->EyeVectors( &vecAiming, &right, &up); Vector vecSpread = VECTOR_CONE_4DEGREES; // Get endpoint float x, y, z; do { x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); z = x*x+y*y; } while (z > 1); Vector vecDir = vecAiming + x * vecSpread.x * right + y * vecSpread.y * up; Vector vecEnd = vecSrc + vecDir * weapon_laserrifle_range.GetFloat(); trace_t tr; float damagefactor = TFGameRules()->WeaponTraceLine(vecSrc, vecEnd, MASK_SHOT, pPlayer, DMG_ENERGYBEAM, &tr); // Hit target? if (tr.fraction != 1.0) { CBaseEntity *pEntity = CBaseEntity::Instance(tr.u.ent); if ( pEntity ) { ClearMultiDamage(); float flDamage = GetDamage( (tr.endpos - vecSrc).Length(), tr.hitgroup ); flDamage *= damagefactor; pEntity->TraceAttack( CTakeDamageInfo( pPlayer, pPlayer, flDamage, DMG_ENERGYBEAM ), vecDir, &tr ); ApplyMultiDamage( pPlayer, pPlayer ); } g_pEffects->EnergySplash( tr.endpos, tr.plane.normal ); } // Get hacked gun position AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, NULL, &right, NULL ); Vector vecTracerSrc = vecSrc + Vector (0,0,-8) + right * 12 + vecDir * 16; // Laser beam CBroadcastRecipientFilter filter; te->BeamPoints( filter, 0.0, &vecTracerSrc, &tr.endpos, m_iSpriteTexture, 0, // Halo index 0, // Start frame 0, // Frame rate 0.2, // Life 15, // Width 15, // EndWidth 0, // FadeLength 0, // Amplitude 200, // r 200, // g 255, // b 255, // a 255 ); // speed pPlayer->m_iAmmo[m_iPrimaryAmmoType]--; m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate(); CheckRemoveDisguise(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponCombat_ChargeablePlasma::ItemPostFrame( void ) { CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); if (!pOwner) return; if ( UsesClipsForAmmo1() ) { CheckReload(); } // If burst shots are firing, ignore input if ( m_iBurstShotsRemaining > 0 ) { if ( gpGlobals->curtime < m_flNextBurstShotTime ) return; if ( m_iClip1 > 0 ) { PrimaryAttack(); } m_iBurstShotsRemaining--; m_flNextBurstShotTime = gpGlobals->curtime + BURST_FIRE_RATE; m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate(); return; } // Handle charge firing if ( m_iClip1 > 0 && GetShieldState() == SS_DOWN && !m_bInReload ) { if ( (pOwner->m_nButtons & IN_ATTACK ) ) { if (m_bHasCharge) { if ( !m_bCharging && (m_flNextPrimaryAttack <= gpGlobals->curtime) ) { m_bCharging = true; m_flChargeStartTime = gpGlobals->curtime; // Get a lock target right now m_hLockTarget = GetLockTarget(); } } else { // Fire the plasma shot if (m_flNextPrimaryAttack <= gpGlobals->curtime) PrimaryAttack(); } } else if ( m_bCharging ) { m_bCharging = false; // Fire the plasma shot PrimaryAttack(); // We might be firing a burst shot if (m_bHasBurstShot) { if ( m_flPower >= (MAX_CHARGED_TIME * 0.5) ) { if ( m_flPower >= MAX_CHARGED_TIME ) { m_iBurstShotsRemaining = 2; } else { m_iBurstShotsRemaining = 1; } m_flNextBurstShotTime = gpGlobals->curtime + BURST_FIRE_RATE; } } } } // Reload button if ( m_iBurstShotsRemaining == 0 && !m_bCharging ) { if ( pOwner->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload ) { Reload(); } } // Prevent shield post frame if we're not ready to attack, or we're charging AllowShieldPostFrame( !m_bCharging && ((m_flNextPrimaryAttack <= gpGlobals->curtime) || m_bInReload) ); }