diff options
Diffstat (limited to 'game/client/tf/c_tf_passtime_logic.cpp')
| -rw-r--r-- | game/client/tf/c_tf_passtime_logic.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/game/client/tf/c_tf_passtime_logic.cpp b/game/client/tf/c_tf_passtime_logic.cpp new file mode 100644 index 0000000..8865155 --- /dev/null +++ b/game/client/tf/c_tf_passtime_logic.cpp @@ -0,0 +1,263 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "tempent.h" +#include "c_tf_passtime_logic.h" +#include "tf_hud_passtime_reticle.h" +#include "passtime_convars.h" +#include "passtime_game_events.h" +#include "tf_shareddefs.h" +#include "tf_classdata.h" +#include "c_tf_player.h" +#include "c_func_passtime_goal.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +void C_TFPasstimeLogic::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + m_pBallReticle = new C_PasstimeBallReticle(); + m_pPassReticle = new C_PasstimePassReticle(); + for( auto *pGoal : C_FuncPasstimeGoal::GetAutoList() ) + { + m_pGoalReticles.AddToTail( new C_PasstimeGoalReticle( + static_cast<C_FuncPasstimeGoal*>( pGoal ) ) ); + } + } +} + +//----------------------------------------------------------------------------- +C_TFPasstimeLogic* g_pPasstimeLogic; +extern ConVar hud_fastswitch; + +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT( C_TFPasstimeLogic, DT_TFPasstimeLogic, CTFPasstimeLogic ) + RecvPropEHandle( RECVINFO( m_hBall ) ), + RecvPropArray( RecvPropVector( RECVINFO( m_trackPoints[0] ) ), m_trackPoints ), + RecvPropInt( RECVINFO( m_iNumSections ) ), + RecvPropInt( RECVINFO( m_iCurrentSection ) ), + RecvPropFloat( RECVINFO( m_flMaxPassRange ) ), + RecvPropInt( RECVINFO( m_iBallPower ), 8 ), + RecvPropFloat( RECVINFO( m_flPackSpeed ) ), + RecvPropArray3( RECVINFO_ARRAY( m_bPlayerIsPackMember ), RecvPropInt( RECVINFO( m_bPlayerIsPackMember[0] ) ) ), +END_RECV_TABLE() + +LINK_ENTITY_TO_CLASS( passtime_logic, C_TFPasstimeLogic ); + +//----------------------------------------------------------------------------- +C_TFPasstimeLogic::C_TFPasstimeLogic() +{ + m_pBallReticle = nullptr; + m_pPassReticle = nullptr; + memset( m_apPackBeams, 0, sizeof( m_apPackBeams ) ); + memset( m_bPlayerIsPackMember, 0, sizeof( m_bPlayerIsPackMember ) ); + for( int i = 0; i < m_trackPoints.Count(); ++i ) + { + m_trackPoints.GetForModify(i).Zero(); + } + + g_pPasstimeLogic = this; +} + +//----------------------------------------------------------------------------- +C_TFPasstimeLogic::~C_TFPasstimeLogic() +{ + delete m_pBallReticle; + m_pGoalReticles.PurgeAndDeleteElements(); + delete m_pPassReticle; + + // Don't set g_pPasstimeLogic to null here because sometimes this destructor + // happens after the contructor of the new object + // FIXME: what's the right way to do this? +} + +//----------------------------------------------------------------------------- +void C_TFPasstimeLogic::Spawn() +{ +} + +//----------------------------------------------------------------------------- +void C_TFPasstimeLogic::ClientThink() +{ + BaseClass::ClientThink(); + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + m_pBallReticle->OnClientThink(); + for ( auto *pGoal : m_pGoalReticles ) + { + pGoal->OnClientThink(); + } + m_pPassReticle->OnClientThink(); + UpdateBeams(); +} + +//----------------------------------------------------------------------------- +void C_TFPasstimeLogic::DestroyBeams( C_PasstimeBall *pBall ) +{ + for ( CNewParticleEffect *pBeam : m_apPackBeams ) + { + if ( pBeam ) + { + pBall->ParticleProp()->StopEmission( pBeam ); + } + } + memset( m_apPackBeams, 0, sizeof( m_apPackBeams ) ); +} + +//----------------------------------------------------------------------------- +void C_TFPasstimeLogic::DestroyBeam( int i, C_PasstimeBall *pBall ) +{ + CNewParticleEffect *pBeam = m_apPackBeams[i]; + if ( pBeam ) + { + pBall->ParticleProp()->StopEmissionAndDestroyImmediately( pBeam ); + m_apPackBeams[i] = nullptr; + } +} + +//----------------------------------------------------------------------------- +void C_TFPasstimeLogic::UpdateBeams() +{ + C_PasstimeBall *pBall = GetBall(); + if ( !pBall ) + { + return; + } + + C_TFPlayer *pCarrier = pBall->GetCarrier(); + if ( !pCarrier ) + { + DestroyBeams( pBall ); + return; + } + + const char *pEffectName = "passtime_beam"; + CParticleProperty *pParticles = pBall->ParticleProp(); + + for ( int i = 1; i <= MAX_PLAYERS; ++i ) + { + if ( !m_bPlayerIsPackMember[i] ) + { + DestroyBeam( i, pBall ); + continue; + } + + CTFPlayer *pPlayer = (CTFPlayer*) UTIL_PlayerByIndex( i ); + if ( !pPlayer || ( pPlayer == pCarrier ) || !pPlayer->IsAlive() ) + { + DestroyBeam( i, pBall ); + continue; + } + + if ( !m_apPackBeams[i] ) + { + CNewParticleEffect *pBeam = pParticles->Create( pEffectName, PATTACH_ABSORIGIN_FOLLOW ); + pParticles->AddControlPoint( pBeam, 1, pPlayer, PATTACH_ABSORIGIN_FOLLOW, 0, Vector(0,0,16) ); + m_apPackBeams[i] = pBeam; + } + } +} + +//----------------------------------------------------------------------------- +void C_TFPasstimeLogic::GetTrackPoints( Vector (&points)[16] ) +{ + memcpy( points, m_trackPoints.Base(), sizeof(points) ); +} + +//----------------------------------------------------------------------------- +bool C_TFPasstimeLogic::GetImportantEntities( C_PasstimeBall **ppBall, C_TFPlayer **ppCarrier, C_TFPlayer **ppHomingTarget ) const +{ + C_PasstimeBall *pBall = GetBall(); + if ( !pBall ) + { + return false; + } + + if ( ppBall ) + { + *ppBall = pBall; + } + + if ( ppCarrier ) + { + *ppCarrier = pBall->GetCarrier(); + } + + if ( ppHomingTarget ) + { + *ppHomingTarget = ToTFPlayer( pBall->GetHomingTarget() ); + } + + return true; +} + +//----------------------------------------------------------------------------- +bool C_TFPasstimeLogic::GetBallReticleTarget( C_BaseEntity **ppEnt, bool *bHomingActive ) const +{ + Assert( ppEnt ); + if ( !ppEnt ) + { + return false; + } + + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalPlayer ) + { + return false; + } + + C_PasstimeBall *pBall = 0; + C_TFPlayer *pCarrier = 0, *pHomingTarget = 0; + if ( !GetImportantEntities( &pBall, &pCarrier, &pHomingTarget ) ) + { + return false; + } + + C_BaseEntity *pEnt = pCarrier ? pCarrier : (C_BaseEntity*)pBall; + if ( !pEnt + || (pEnt == pLocalPlayer) + || (pEnt->GetEffects() & EF_NODRAW) + || ((pEnt->GetTeamNumber() != TEAM_UNASSIGNED) + && (pEnt->GetTeamNumber() != pLocalPlayer->GetTeamNumber())) + || (pLocalPlayer->IsObserver() && (GetSpectatorMode() != OBS_MODE_ROAMING) && (GetSpectatorTarget() == pEnt->index)) ) + { + return false; + } + + *ppEnt = pEnt; + if ( bHomingActive ) + { + *bHomingActive = pHomingTarget != 0; + } + + return true; +} + +//----------------------------------------------------------------------------- +bool C_TFPasstimeLogic::BCanPlayerPickUpBall( C_TFPlayer *pPlayer ) const +{ + return pPlayer + && pPlayer->IsAllowedToPickUpFlag() + && pPlayer->IsAlive() // NOTE: it's possible to be alive and dead at the same time + && !pPlayer->m_Shared.InCond( TF_COND_INVULNERABLE ) + && !pPlayer->m_Shared.InCond( TF_COND_PHASE ) + && !pPlayer->m_Shared.InCond( TF_COND_INVULNERABLE_WEARINGOFF ) + && !pPlayer->m_Shared.InCond( TF_COND_SELECTED_TO_TELEPORT ) + && !pPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) + && !pPlayer->m_Shared.InCond( TF_COND_TAUNTING ) + && !pPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) + && !pPlayer->m_Shared.IsControlStunned() + && !pPlayer->m_Shared.IsStealthed() + && !pPlayer->m_Shared.IsCarryingObject(); +} + |