//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: TF2 specific CBaseCombatCharacter code. // //=============================================================================// #include "cbase.h" #include "basecombatcharacter.h" #include "engine/IEngineSound.h" #include "tf_player.h" #include "tf_stats.h" extern char *g_pszEMPPulseStart; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CBaseCombatCharacter::HasPowerup( int iPowerup ) { Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); return ( m_iPowerups & (1 << iPowerup) ) != 0; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CBaseCombatCharacter::CanPowerupEver( int iPowerup ) { Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); // Only objects use power if ( iPowerup == POWERUP_POWER ) return false; // Accept everything else return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CBaseCombatCharacter::CanPowerupNow( int iPowerup ) { Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); if ( !CanPowerupEver(iPowerup) ) return false; switch( iPowerup ) { case POWERUP_BOOST: { // Am I taking EMP damage, or is a technician trying to drain me? if ( HasPowerup( POWERUP_EMP ) || ( (m_flPowerupAttemptTimes[POWERUP_EMP] + 0.5) > gpGlobals->curtime ) ) { // Reduce EMP time m_flPowerupEndTimes[POWERUP_EMP] -= 0.05; // Don't apply any boost effects return false; } } break; case POWERUP_EMP: { // Was I just boosted? If so, I don't take EMP damage for a bit if ( (m_flPowerupAttemptTimes[POWERUP_BOOST] + 0.5) > gpGlobals->curtime ) return false; } break; default: break; } return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseCombatCharacter::SetPowerup( int iPowerup, bool bState, float flTime, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier ) { Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); // Some powerups trigger their on state continuously, as opposed to turning it on for some time. bool bTriggerStart = ( bState && !HasPowerup( iPowerup ) ); if ( bState && iPowerup == POWERUP_BOOST ) { // Health boost always triggers bTriggerStart = true; } bool bHadPowerup = false; if ( HasPowerup( iPowerup ) && !bState ) { bHadPowerup = true; } if ( bState ) { m_iPowerups |= (1 << iPowerup); } else { m_iPowerups &= ~(1 << iPowerup); } // Fire start/end triggers if ( bTriggerStart ) { PowerupStart( iPowerup, flAmount, pAttacker, pDamageModifier ); } else if ( bHadPowerup ) { PowerupEnd( iPowerup ); } // If we've got an active powerup, keep thinking if ( m_iPowerups ) { SetContextThink( PowerupThink, gpGlobals->curtime + 0.1, POWERUP_THINK_CONTEXT ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseCombatCharacter::PowerupThink( void ) { // If we don't have any powerups, stop thinking if ( !m_iPowerups ) return; // Check all the powerups for ( int i = 0; i < MAX_POWERUPS; i++ ) { // Don't check power, because it never runs out naturally if ( i == POWERUP_POWER ) continue; if ( m_iPowerups & (1 << i) ) { // Should it finish now? if ( m_flPowerupEndTimes[i] < gpGlobals->curtime ) { SetPowerup( i, false ); } } } SetNextThink( gpGlobals->curtime + 0.1, POWERUP_THINK_CONTEXT ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CBaseCombatCharacter::AttemptToPowerup( int iPowerup, float flTime, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier ) { Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); // Ignore it if I'm dead if ( !IsAlive() ) return false; m_flPowerupAttemptTimes[iPowerup] = gpGlobals->curtime; // If we can't be powerup this type, abort if ( !CanPowerupNow( iPowerup ) ) return false; // Get the correct duration flTime = PowerupDuration( iPowerup, flTime ); m_flPowerupEndTimes[iPowerup] = MAX( m_flPowerupEndTimes[iPowerup], gpGlobals->curtime + flTime ); // Turn it on SetPowerup( iPowerup, true, flTime, flAmount, pAttacker, pDamageModifier ); // Add the damage modifier to the player if ( pDamageModifier ) { pDamageModifier->AddModifierToEntity( this ); } return true; } //----------------------------------------------------------------------------- // Purpose: Powerup has just started //----------------------------------------------------------------------------- void CBaseCombatCharacter::PowerupStart( int iPowerup, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier ) { Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS ); switch( iPowerup ) { case POWERUP_BOOST: { // Players can be boosted over their max int iMaxBoostedHealth; if ( IsPlayer() ) { iMaxBoostedHealth = GetMaxHealth() + GetMaxHealth() / 2; } else { iMaxBoostedHealth = GetMaxHealth(); } // Can we boost health further? if ( GetHealth() < iMaxBoostedHealth ) { int maxHealthToAdd = iMaxBoostedHealth - GetHealth(); // It uses floating point in here so it doesn't lose the fractional healing part on small frame times. float flHealthToAdd = flAmount + m_flFractionalBoost; int nHealthToAdd = (int)flHealthToAdd; m_flFractionalBoost = flHealthToAdd - nHealthToAdd; if ( nHealthToAdd ) { int nHealthAdded = MIN( nHealthToAdd, maxHealthToAdd ); if ( IsPlayer() ) { ((CBaseTFPlayer*)this)->TakeHealthBoost( nHealthAdded, GetMaxHealth(), 25 ); } else { TakeHealth( nHealthAdded, DMG_GENERIC ); } TFStats()->IncrementPlayerStat( pAttacker, TF_PLAYER_STAT_HEALTH_GIVEN, nHealthAdded ); } } } break; case POWERUP_EMP: { // EMP removes adrenalin rush SetPowerup( POWERUP_RUSH, false ); } break; default: break; } }