mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-04 18:09:53 +03:00
1
This commit is contained in:
397
game/shared/tf/tf_condition.cpp
Normal file
397
game/shared/tf/tf_condition.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Condition Objects
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "tf_condition.h"
|
||||
|
||||
#ifdef GAME_DLL
|
||||
#include "tf_player.h"
|
||||
#else
|
||||
#include "c_tf_player.h"
|
||||
#include "achievementmgr.h"
|
||||
#include "baseachievement.h"
|
||||
#include "achievements_tf.h"
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
BEGIN_PREDICTION_DATA_NO_BASE( CTFConditionList )
|
||||
DEFINE_PRED_FIELD( _condition_bits, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
BEGIN_RECV_TABLE_NOBASE( CTFConditionList, DT_TFPlayerConditionListExclusive )
|
||||
RecvPropInt( RECVINFO( _condition_bits ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
#else
|
||||
|
||||
BEGIN_SEND_TABLE_NOBASE( CTFConditionList, DT_TFPlayerConditionListExclusive )
|
||||
SendPropInt( SENDINFO( _condition_bits ), MIN( TF_COND_LAST, 32 ), SPROP_UNSIGNED ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Ctor
|
||||
//-----------------------------------------------------------------------------
|
||||
CTFConditionList::CTFConditionList()
|
||||
{
|
||||
_condition_bits = _old_condition_bits = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Condition factory.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CTFConditionList::Add( ETFCond type, float duration, CTFPlayer* outer, CBaseEntity* provider /*= NULL*/ )
|
||||
{
|
||||
#ifdef GAME_DLL
|
||||
return _Add( type, duration, outer, provider );
|
||||
#else
|
||||
return type == TF_COND_CRITBOOSTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CTFConditionList::_Add( ETFCond type, float duration, CTFPlayer* outer, CBaseEntity* provider /*= NULL*/ )
|
||||
{
|
||||
// If we already have a condition of this type, ask it to handle the addition of another.
|
||||
for ( int i = 0; i < _conditions.Count(); ++i )
|
||||
{
|
||||
if ( _conditions[i]->GetType() == type )
|
||||
{
|
||||
_conditions[i]->Add( duration );
|
||||
_conditions[i]->SetProvider( provider );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new condition.
|
||||
CTFCondition* newCond = NULL;
|
||||
switch ( type )
|
||||
{
|
||||
// TODO: Register new conditions anonymously instead of switching.
|
||||
case TF_COND_CRITBOOSTED:
|
||||
newCond = new CTFCondition_CritBoost( type, duration, outer, provider );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( newCond )
|
||||
{
|
||||
_condition_bits |= (1<<type);
|
||||
_old_condition_bits |= (1<<type);
|
||||
|
||||
_conditions.AddToTail( newCond );
|
||||
newCond->OnAdded();
|
||||
newCond->SetProvider( provider );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Remove a condition from the player.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CTFConditionList::Remove( ETFCond type, bool ignore_duration )
|
||||
{
|
||||
#ifdef GAME_DLL
|
||||
bool bConditionListHandledRemoval = _Remove( type, ignore_duration );
|
||||
|
||||
// The condition list only handles one type of condition. Written slightly weird
|
||||
// to avoid unused variable warnings with asserts disabled.
|
||||
if ( bConditionListHandledRemoval )
|
||||
{
|
||||
Assert( type == TF_COND_CRITBOOSTED );
|
||||
}
|
||||
#endif
|
||||
return type == TF_COND_CRITBOOSTED;
|
||||
}
|
||||
|
||||
bool CTFConditionList::_Remove( ETFCond type, bool ignore_duration )
|
||||
{
|
||||
for ( int i=_conditions.Count()-1; i>=0; --i )
|
||||
{
|
||||
CTFCondition* cond = _conditions[i];
|
||||
if ( !cond || cond->GetType() != type )
|
||||
continue;
|
||||
|
||||
if ( cond->UsesMinDuration() && !ignore_duration && cond->GetMinDuration() > 0 )
|
||||
{
|
||||
cond->SetMaxDuration( cond->GetMinDuration() );
|
||||
continue; // Can't remove conditions that haven't expired.
|
||||
}
|
||||
|
||||
_conditions.Remove( i );
|
||||
|
||||
_condition_bits &= ~(1<<type);
|
||||
_old_condition_bits &= ~(1<<type);
|
||||
|
||||
cond->OnRemoved();
|
||||
delete cond;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Clear all conditions from the player.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFConditionList::RemoveAll()
|
||||
{
|
||||
_condition_bits = 0;
|
||||
_old_condition_bits = 0;
|
||||
|
||||
for ( int i=0; i<_conditions.Count(); ++i )
|
||||
{
|
||||
_conditions[i]->OnRemoved();
|
||||
}
|
||||
_conditions.PurgeAndDeleteElements();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Checks if we have at least one of a given condition applied.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CTFConditionList::InCond( ETFCond type ) const
|
||||
{
|
||||
return ( ( _condition_bits & (1<<type) ) != 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CTFConditionList::GetProvider( ETFCond type ) const
|
||||
{
|
||||
CBaseEntity *pProvider = NULL;
|
||||
for ( int i = 0; i < _conditions.Count(); ++i )
|
||||
{
|
||||
if ( _conditions[i]->GetType() == type )
|
||||
{
|
||||
pProvider = _conditions[i]->GetProvider();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pProvider;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Client/Server periodic condition think.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFConditionList::Think()
|
||||
{
|
||||
for ( int i=0; i<_conditions.Count(); ++i )
|
||||
{
|
||||
_conditions[i]->OnThink();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Server only per-frame think.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFConditionList::ServerThink()
|
||||
{
|
||||
#ifdef GAME_DLL
|
||||
for ( int i=0; i<_conditions.Count(); ++i )
|
||||
{
|
||||
CTFCondition* cond = _conditions[i];
|
||||
if ( cond->GetMaxDuration() > PERMANENT_CONDITION ||
|
||||
cond->GetMinDuration() > PERMANENT_CONDITION )
|
||||
{
|
||||
// Reduce the duration over time.
|
||||
float reduction = gpGlobals->frametime;
|
||||
|
||||
// Healable conditions expire faster when we have healers.
|
||||
int numHealers = cond->GetOuter()->m_Shared.GetNumHealers();
|
||||
if ( cond->IsHealable() && numHealers > 0 )
|
||||
{
|
||||
reduction += numHealers * reduction * 4;
|
||||
}
|
||||
|
||||
// Decrement min duration.
|
||||
if ( cond->GetMinDuration() > PERMANENT_CONDITION )
|
||||
{
|
||||
cond->SetMinDuration( MAX( cond->GetMinDuration() - reduction, 0 ) );
|
||||
}
|
||||
|
||||
// Decrement max duration.
|
||||
if ( cond->GetMaxDuration() > PERMANENT_CONDITION )
|
||||
{
|
||||
cond->SetMaxDuration( MAX( cond->GetMaxDuration() - reduction, 0 ) );
|
||||
|
||||
if ( cond->GetMaxDuration() < cond->GetMinDuration() )
|
||||
{
|
||||
cond->SetMaxDuration( cond->GetMinDuration() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( cond->GetMaxDuration() == 0 )
|
||||
{
|
||||
Remove( cond->GetType() );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_conditions[i]->OnServerThink();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFConditionList::OnPreDataChanged( void )
|
||||
{
|
||||
// _old_condition_bits = _condition_bits;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFConditionList::OnDataChanged( CTFPlayer* outer )
|
||||
{
|
||||
// Is there a way to improve this by hooking directly into network state changed?
|
||||
if ( _old_condition_bits != _condition_bits )
|
||||
{
|
||||
UpdateClientConditions( outer );
|
||||
|
||||
_old_condition_bits = _condition_bits;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates or destroys conditions to make sure our state matches the server.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFConditionList::UpdateClientConditions( CTFPlayer* outer )
|
||||
{
|
||||
int nCondChanged = _condition_bits ^ _old_condition_bits;
|
||||
int nCondAdded = nCondChanged & _condition_bits;
|
||||
int nCondRemoved = nCondChanged & _old_condition_bits;
|
||||
|
||||
int i;
|
||||
for ( i=0;i<TF_COND_LAST;i++ )
|
||||
{
|
||||
if ( nCondAdded & (1<<i) )
|
||||
{
|
||||
_Add( (ETFCond)i, PERMANENT_CONDITION, outer );
|
||||
}
|
||||
else if ( nCondRemoved & (1<<i) )
|
||||
{
|
||||
_Remove( (ETFCond)i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Ctor
|
||||
//-----------------------------------------------------------------------------
|
||||
CTFCondition::CTFCondition( ETFCond type, float duration, CTFPlayer* outer, CBaseEntity* provider /*= NULL*/ )
|
||||
: _type( type ),
|
||||
_min_duration( 0 ),
|
||||
_max_duration( duration ),
|
||||
_outer( outer ),
|
||||
_provider( provider )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Dtor
|
||||
//-----------------------------------------------------------------------------
|
||||
CTFCondition::~CTFCondition()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called if we try to add another condition of a type we already have.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFCondition::Add( float duration )
|
||||
{
|
||||
if ( duration != PERMANENT_CONDITION )
|
||||
{
|
||||
// If our new duration is not permanent, is shorter than
|
||||
// our current duration, and is longer than our min duration
|
||||
// make it our new min duration.
|
||||
if ( GetMaxDuration() == PERMANENT_CONDITION ||
|
||||
duration < GetMaxDuration() )
|
||||
{
|
||||
if ( duration > GetMinDuration() )
|
||||
SetMinDuration( duration );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( GetMaxDuration() != PERMANENT_CONDITION )
|
||||
{
|
||||
// If our current duration is not permanent and we are adding a
|
||||
// permanent duration, make our old finite duration the new min duration.
|
||||
// This ensures we last at least that long.
|
||||
SetMinDuration( GetMaxDuration() );
|
||||
}
|
||||
|
||||
SetMaxDuration( duration );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Crit Boost
|
||||
//=============================================================================
|
||||
CTFCondition_CritBoost::CTFCondition_CritBoost( ETFCond type, float duration, CTFPlayer* outer, CBaseEntity* provider /*= NULL*/ )
|
||||
: CTFCondition( type, duration, outer, provider )
|
||||
{
|
||||
Assert( type == TF_COND_CRITBOOSTED );
|
||||
}
|
||||
|
||||
void CTFCondition_CritBoost::OnAdded()
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
GetOuter()->m_Shared.UpdateCritBoostEffect();
|
||||
|
||||
if ( GetOuter()->IsLocalPlayer() && GetOuter()->IsPlayerClass( TF_CLASS_HEAVYWEAPONS ) )
|
||||
{
|
||||
g_AchievementMgrTF.OnAchievementEvent( ACHIEVEMENT_TF_HEAVY_RECEIVE_UBER_GRIND );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTFCondition_CritBoost::OnRemoved()
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
GetOuter()->m_Shared.UpdateCritBoostEffect();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTFCondition_CritBoost::OnThink()
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
if ( GetOuter()->m_pCritBoostEffect )
|
||||
{
|
||||
CBaseEntity *pWeapon = NULL;
|
||||
// Use GetRenderedWeaponModel() instead?
|
||||
if ( GetOuter()->IsLocalPlayer() )
|
||||
{
|
||||
pWeapon = GetOuter()->GetViewModel(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pWeapon = GetOuter()->GetActiveWeapon();
|
||||
}
|
||||
|
||||
// Transfer the crit boosted effect if we've switched weapons
|
||||
if ( GetOuter()->m_pCritBoostEffect->GetOwner() != pWeapon )
|
||||
{
|
||||
GetOuter()->m_Shared.UpdateCritBoostEffect();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTFCondition_CritBoost::OnServerThink()
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user