diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/tf_logic_player_destruction.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/tf/tf_logic_player_destruction.cpp')
| -rw-r--r-- | game/shared/tf/tf_logic_player_destruction.cpp | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/game/shared/tf/tf_logic_player_destruction.cpp b/game/shared/tf/tf_logic_player_destruction.cpp new file mode 100644 index 0000000..927cda4 --- /dev/null +++ b/game/shared/tf/tf_logic_player_destruction.cpp @@ -0,0 +1,468 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Entities for use in the Robot Destruction TF2 game mode. +// +//=========================================================================// + +#include "cbase.h" +#include "tf_logic_player_destruction.h" + +#ifdef GAME_DLL +#include "tf_player.h" +#include "entity_capture_flag.h" +#include "tf_obj_dispenser.h" +#include "tf_gamerules.h" +#else +#include "c_tf_player.h" +#endif // GAME_DLL + +BEGIN_DATADESC( CPlayerDestructionDispenser ) +END_DATADESC() + +IMPLEMENT_NETWORKCLASS_ALIASED( PlayerDestructionDispenser, DT_PlayerDestructionDispenser ) +LINK_ENTITY_TO_CLASS( pd_dispenser, CPlayerDestructionDispenser ); + +BEGIN_NETWORK_TABLE( CPlayerDestructionDispenser, DT_PlayerDestructionDispenser ) +END_NETWORK_TABLE() + +#ifdef GAME_DLL +BEGIN_DATADESC( CTFPlayerDestructionLogic ) + DEFINE_KEYFIELD( m_iszPropModelName, FIELD_STRING, "prop_model_name" ), + DEFINE_KEYFIELD( m_iszPropDropSound, FIELD_STRING, "prop_drop_sound" ), + DEFINE_KEYFIELD( m_iszPropPickupSound, FIELD_STRING, "prop_pickup_sound" ), + DEFINE_KEYFIELD( m_nMinPoints, FIELD_INTEGER, "min_points" ), + DEFINE_KEYFIELD( m_nPointsPerPlayer, FIELD_INTEGER, "points_per_player" ), + DEFINE_KEYFIELD( m_nFlagResetDelay, FIELD_INTEGER, "flag_reset_delay" ), + DEFINE_KEYFIELD( m_nHealDistance, FIELD_INTEGER, "heal_distance" ), + + DEFINE_INPUTFUNC( FIELD_VOID, "ScoreRedPoints", InputScoreRedPoints ), + DEFINE_INPUTFUNC( FIELD_VOID, "ScoreBluePoints", InputScoreBluePoints ), + DEFINE_INPUTFUNC( FIELD_VOID, "EnableMaxScoreUpdating", InputEnableMaxScoreUpdating ), + DEFINE_INPUTFUNC( FIELD_VOID, "DisableMaxScoreUpdating", InputDisableMaxScoreUpdating ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetCountdownTimer", InputSetCountdownTimer ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetCountdownImage", InputSetCountdownImage ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetFlagResetDelay", InputSetFlagResetDelay ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetPointsOnPlayerDeath", InputSetPointsOnPlayerDeath ), + + DEFINE_OUTPUT( m_OnRedScoreChanged, "OnRedScoreChanged" ), + DEFINE_OUTPUT( m_OnBlueScoreChanged, "OnBlueScoreChanged" ), + DEFINE_OUTPUT( m_OnCountdownTimerExpired, "OnCountdownTimerExpired" ), +END_DATADESC() +#endif + +LINK_ENTITY_TO_CLASS( tf_logic_player_destruction, CTFPlayerDestructionLogic ); +IMPLEMENT_NETWORKCLASS_ALIASED( TFPlayerDestructionLogic, DT_TFPlayerDestructionLogic ) + +BEGIN_NETWORK_TABLE( CTFPlayerDestructionLogic, DT_TFPlayerDestructionLogic ) +#ifdef CLIENT_DLL + RecvPropEHandle( RECVINFO( m_hRedTeamLeader ) ), + RecvPropEHandle( RECVINFO( m_hBlueTeamLeader ) ), + RecvPropString( RECVINFO( m_iszCountdownImage ) ), + RecvPropBool( RECVINFO( m_bUsingCountdownImage ) ), +#else + SendPropEHandle( SENDINFO( m_hRedTeamLeader ) ), + SendPropEHandle( SENDINFO( m_hBlueTeamLeader ) ), + SendPropStringT( SENDINFO( m_iszCountdownImage ) ), + SendPropBool( SENDINFO( m_bUsingCountdownImage ) ), +#endif +END_NETWORK_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFPlayerDestructionLogic::CTFPlayerDestructionLogic() +{ +#ifdef GAME_DLL + m_iszPropModelName = MAKE_STRING( "models/flag/flag.mdl" ); + ListenForGameEvent( "player_disconnect" ); + m_bMaxScoreUpdatingAllowed = false; + m_nFlagResetDelay = 60; + m_nHealDistance = 450; + m_nPointsOnPlayerDeath = 1; +#endif // GAME_DLL + + m_hRedTeamLeader = NULL; + m_hBlueTeamLeader = NULL; + + m_bUsingCountdownImage = false; + +#ifdef CLIENT_DLL + m_iszCountdownImage[0] = '\0'; +#else + m_iszCountdownImage.Set( NULL_STRING ); +#endif +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFPlayerDestructionLogic* CTFPlayerDestructionLogic::GetPlayerDestructionLogic() +{ + return assert_cast< CTFPlayerDestructionLogic* >( CTFRobotDestructionLogic::GetRobotDestructionLogic() ); +} + + +#ifdef GAME_DLL +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPlayerDestructionLogic::Precache() +{ + BaseClass::Precache(); + + PrecacheModel( GetPropModelName() ); + PrecacheScriptSound( STRING( m_iszPropDropSound ) ); + PrecacheScriptSound( STRING( m_iszPropPickupSound ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const char *CTFPlayerDestructionLogic::GetPropModelName() const +{ + return STRING( m_iszPropModelName ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPlayerDestructionLogic::CalcTeamLeader( int iTeam ) +{ + // team leader's changed team, recalculate team leader for that team + if ( m_hRedTeamLeader.Get() && m_hRedTeamLeader.Get()->GetTeamNumber() != TF_TEAM_RED ) + { + m_hRedTeamLeader = NULL; + CalcTeamLeader( TF_TEAM_RED ); + } + if ( m_hBlueTeamLeader.Get() && m_hBlueTeamLeader.Get()->GetTeamNumber() != TF_TEAM_BLUE ) + { + m_hBlueTeamLeader = NULL; + CalcTeamLeader( TF_TEAM_BLUE ); + } + + CUtlVector< CTFPlayer * > playerVector; + CollectPlayers( &playerVector, iTeam, COLLECT_ONLY_LIVING_PLAYERS ); + + CTFPlayer *pTeamLeader = iTeam == TF_TEAM_RED ? m_hRedTeamLeader.Get() : m_hBlueTeamLeader.Get(); + int iCurrentLeadingPoint = 0; + if ( pTeamLeader && pTeamLeader->HasItem() ) + { + CCaptureFlag *pFlag = dynamic_cast<CCaptureFlag*>( pTeamLeader->GetItem() ); + if ( pFlag ) + { + iCurrentLeadingPoint = pFlag->GetPointValue(); + } + } + else + { + // reset team leader + pTeamLeader = NULL; + if ( iTeam == TF_TEAM_RED ) + { + m_hRedTeamLeader = NULL; + UTIL_Remove( m_hRedDispenser ); + m_hRedDispenser = NULL; + } + else + { + m_hBlueTeamLeader = NULL; + UTIL_Remove( m_hBlueDispenser ); + m_hBlueDispenser = NULL; + } + } + + // find new team leader + CTFPlayer *pNewTeamLeader = NULL; + FOR_EACH_VEC( playerVector, i ) + { + CTFPlayer *pPlayer = playerVector[i]; + if ( pPlayer == pTeamLeader ) + continue; + + // community request from Watergate author to never have a SPY be the team leader + if ( pPlayer->HasItem() && !pPlayer->IsPlayerClass( TF_CLASS_SPY ) ) + { + CCaptureFlag *pFlag = dynamic_cast< CCaptureFlag* >( pPlayer->GetItem() ); + if ( pFlag && pFlag->GetPointValue() > iCurrentLeadingPoint ) + { + iCurrentLeadingPoint = pFlag->GetPointValue(); + pNewTeamLeader = pPlayer; + } + } + } + + // set new leader + if ( pNewTeamLeader ) + { + CObjectDispenser *pDispenser = NULL; + if ( iTeam == TF_TEAM_RED ) + { + m_hRedTeamLeader = pNewTeamLeader; + + if ( !m_hRedDispenser ) + { + m_hRedDispenser = CreateDispenser( iTeam ); + } + pDispenser = m_hRedDispenser; + } + else + { + m_hBlueTeamLeader = pNewTeamLeader; + + if ( !m_hBlueDispenser ) + { + m_hBlueDispenser = CreateDispenser( iTeam ); + } + pDispenser = m_hBlueDispenser; + } + + if ( pDispenser ) + { + pDispenser->SetOwnerEntity( pNewTeamLeader ); + pDispenser->FollowEntity( pNewTeamLeader ); + pDispenser->SetBuilder( pNewTeamLeader ); + } + } +} + +void CTFPlayerDestructionLogic::FireGameEvent( IGameEvent *pEvent ) +{ + const char* pszName = pEvent->GetName(); + if ( FStrEq( pszName, "player_spawn" ) || FStrEq( pszName, "player_disconnect" ) ) + { + EvaluatePlayerCount(); + return; + } + else if( FStrEq( pszName, "teamplay_pre_round_time_left" ) ) + { + // Eat this event so the RD logic doesn't talk + return; + } + + BaseClass::FireGameEvent( pEvent ); +} + +void CTFPlayerDestructionLogic::OnRedScoreChanged() +{ + m_OnRedScoreChanged.Set( (float)m_nRedScore / m_nMaxPoints, this, this ); +} + +void CTFPlayerDestructionLogic::OnBlueScoreChanged() +{ + m_OnBlueScoreChanged.Set( (float)m_nBlueScore / m_nMaxPoints, this, this ); +} + +void CTFPlayerDestructionLogic::EvaluatePlayerCount() +{ + // Bail if we're not allowed + if ( !m_bMaxScoreUpdatingAllowed ) + return; + + CUtlVector< CTFPlayer* > vecAllPlayers; + CollectPlayers( &vecAllPlayers ); + + m_nMaxPoints = Max( m_nMinPoints, m_nPointsPerPlayer * vecAllPlayers.Count() ); +} + +void CTFPlayerDestructionLogic::InputScoreRedPoints( inputdata_t& inputdata ) +{ + ScorePoints( TF_TEAM_RED, 1, SCORE_CORES_COLLECTED, NULL ); +} + +void CTFPlayerDestructionLogic::InputScoreBluePoints( inputdata_t& inputdata ) +{ + ScorePoints( TF_TEAM_BLUE, 1, SCORE_CORES_COLLECTED, NULL ); +} + +void CTFPlayerDestructionLogic::InputEnableMaxScoreUpdating( inputdata_t& inputdata ) +{ + m_bMaxScoreUpdatingAllowed = true; + EvaluatePlayerCount(); +} + +void CTFPlayerDestructionLogic::InputDisableMaxScoreUpdating( inputdata_t& inputdata ) +{ + EvaluatePlayerCount(); + m_bMaxScoreUpdatingAllowed = false; +} + +void CTFPlayerDestructionLogic::InputSetCountdownTimer( inputdata_t& inputdata ) +{ + int nTime = inputdata.value.Int(); + + if ( nTime > 0 ) + { + SetCountdownEndTime( gpGlobals->curtime + nTime ); + SetThink( &CTFPlayerDestructionLogic::CountdownThink ); + SetNextThink( gpGlobals->curtime + 0.05f ); + } + else + { + SetCountdownEndTime( -1.f ); + SetThink( NULL ); + } +} + +void CTFPlayerDestructionLogic::CountdownThink( void ) +{ + if ( m_flCountdownEndTime > -1.f ) + { + // if we're done, just reset the end time + if ( m_flCountdownEndTime < gpGlobals->curtime ) + { + m_OnCountdownTimerExpired.FireOutput( this, this ); + m_flCountdownEndTime = -1.f; + SetThink( NULL ); + return; + } + } + + SetNextThink( gpGlobals->curtime + 0.05f ); +} + +void CTFPlayerDestructionLogic::InputSetCountdownImage( inputdata_t& inputdata ) +{ + m_bUsingCountdownImage = true; + m_iszCountdownImage = inputdata.value.StringID(); +} + + +void CTFPlayerDestructionLogic::InputSetFlagResetDelay( inputdata_t& inputdata ) +{ + int nDelay = inputdata.value.Int(); + if ( nDelay < 0 ) + { + nDelay = 0; + } + + m_nFlagResetDelay = nDelay; +} + +void CTFPlayerDestructionLogic::InputSetPointsOnPlayerDeath( inputdata_t& inputdata ) +{ + int nPointsOnPlayerDeath = inputdata.value.Int(); + if ( nPointsOnPlayerDeath < 0 ) + { + nPointsOnPlayerDeath = 0; + } + + m_nPointsOnPlayerDeath = nPointsOnPlayerDeath; +} + +CObjectDispenser *CTFPlayerDestructionLogic::CreateDispenser( int iTeam ) +{ + CPlayerDestructionDispenser *pDispenser = static_cast< CPlayerDestructionDispenser* >( CBaseEntity::CreateNoSpawn( "pd_dispenser", vec3_origin, vec3_angle, NULL ) ); + pDispenser->ChangeTeam( iTeam ); + pDispenser->SetObjectFlags( pDispenser->GetObjectFlags() | OF_DOESNT_HAVE_A_MODEL | OF_PLAYER_DESTRUCTION ); + pDispenser->m_iUpgradeLevel = 1; + DispatchSpawn( pDispenser ); + pDispenser->FinishedBuilding(); + pDispenser->AddEffects( EF_NODRAW ); + pDispenser->DisableAmmoPickupSound(); + pDispenser->DisableGenerateMetalSound(); + pDispenser->m_takedamage = DAMAGE_NO; + + CBaseEntity *pTouchTrigger = pDispenser->GetTouchTrigger(); + if ( pTouchTrigger ) + { + pTouchTrigger->FollowEntity( pDispenser ); + } + + return pDispenser; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPlayerDestructionLogic::PlayPropDropSound( CTFPlayer *pPlayer ) +{ + PlaySound( STRING( m_iszPropDropSound ), pPlayer ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPlayerDestructionLogic::PlayPropPickupSound( CTFPlayer *pPlayer ) +{ + PlaySound( STRING( m_iszPropPickupSound ), pPlayer ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPlayerDestructionLogic::PlaySound( const char *pszSound, CTFPlayer *pPlayer ) +{ + EmitSound_t params; + params.m_pSoundName = pszSound; + params.m_flSoundTime = 0; + params.m_pflSoundDuration = 0; + params.m_SoundLevel = SNDLVL_70dB; + CPASFilter filter( pPlayer->GetAbsOrigin() ); + pPlayer->EmitSound( filter, pPlayer->entindex(), params ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPlayerDestructionDispenser::Spawn( void ) +{ + // This cast is for the benefit of GCC + m_fObjectFlags |= (int)OF_DOESNT_HAVE_A_MODEL; + m_takedamage = DAMAGE_NO; + m_iUpgradeLevel = 1; + + TFGameRules()->OnDispenserBuilt( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Finished building +//----------------------------------------------------------------------------- +void CPlayerDestructionDispenser::OnGoActive( void ) +{ + BaseClass::OnGoActive(); + + if ( m_hTouchTrigger ) + { + m_hTouchTrigger->SetParent( GetParent() ); + } + + SetModel( "" ); +} + +//----------------------------------------------------------------------------- +// Spawn the vgui control screens on the object +//----------------------------------------------------------------------------- +void CPlayerDestructionDispenser::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ) +{ + // no panels + return; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFPlayerDestructionLogic::TeamWin( int nTeam ) +{ + if ( TFGameRules() ) + { + TFGameRules()->SetWinningTeam( nTeam, WINREASON_PD_POINTS ); + } +} +#endif // GAME_DLL + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFPlayer *CTFPlayerDestructionLogic::GetTeamLeader( int iTeam ) const +{ + return iTeam == TF_TEAM_RED ? m_hRedTeamLeader.Get() : m_hBlueTeamLeader.Get(); +} + |