source-engine/game/server/tf/entity_currencypack.cpp

347 lines
11 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: CTF CurrencyPack.
//
//=============================================================================//
#include "cbase.h"
#include "items.h"
#include "tf_gamerules.h"
#include "tf_shareddefs.h"
#include "tf_player.h"
#include "tf_team.h"
#include "engine/IEngineSound.h"
#include "entity_currencypack.h"
#include "tf_gamestats.h"
#include "tf_mann_vs_machine_stats.h"
#include "world.h"
#include "particle_parse.h"
#include "player_vs_environment/tf_population_manager.h"
#include "collisionutils.h"
#include "tf_objective_resource.h"
//=============================================================================
//
// CTF CurrencyPack defines.
//
#define TF_CURRENCYPACK_PICKUP_SOUND "MVM.MoneyPickup"
#define TF_CURRENCYPACK_VANISH_SOUND "MVM.MoneyVanish"
#define TF_CURRENCYPACK_BLINK_PERIOD 5.0f // how long pack blinks before it vanishes
#define TF_CURRENCYPACK_BLINK_DURATION 0.25f // how long a blink lasts
#define TF_CURRENCYPACK_GLOW_THINK_TIME 0.1f // how often should we check if cash should glow
LINK_ENTITY_TO_CLASS( item_currencypack_large, CCurrencyPack );
LINK_ENTITY_TO_CLASS( item_currencypack_medium, CCurrencyPackMedium );
LINK_ENTITY_TO_CLASS( item_currencypack_small, CCurrencyPackSmall );
LINK_ENTITY_TO_CLASS( item_currencypack_custom, CCurrencyPackCustom );
IMPLEMENT_SERVERCLASS_ST( CCurrencyPack, DT_CurrencyPack )
SendPropBool( SENDINFO( m_bDistributed ) ),
END_SEND_TABLE()
IMPLEMENT_AUTO_LIST( ICurrencyPackAutoList );
//=============================================================================
//
// CTF CurrencyPack functions.
//
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCurrencyPack::CCurrencyPack()
{
m_nAmount = 0;
m_nWaveNumber = MannVsMachineStats_GetCurrentWave();
m_bTouched = false;
m_bClaimed = false;
m_bDistributed = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCurrencyPack::~CCurrencyPack()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCurrencyPack::UpdateOnRemove( void )
{
BaseClass::UpdateOnRemove();
if ( g_pPopulationManager && !m_bTouched )
{
if ( !m_bDistributed )
{
g_pPopulationManager->OnCurrencyPackFade();
}
DispatchParticleEffect( "mvm_cash_explosion", GetAbsOrigin(), GetAbsAngles() );
}
if ( !m_bDistributed && TFObjectiveResource() )
{
TFObjectiveResource()->AddMvMWorldMoney( -m_nAmount );
}
}
//-----------------------------------------------------------------------------
// Purpose: Always transmitted to clients
//-----------------------------------------------------------------------------
int CCurrencyPack::UpdateTransmitState( void )
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CCurrencyPack::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
return FL_EDICT_ALWAYS;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCurrencyPack::Spawn( void )
{
BaseClass::Spawn();
m_blinkCount = 0;
m_blinkTimer.Invalidate();
SetContextThink( &CCurrencyPack::BlinkThink, gpGlobals->curtime + GetLifeTime() - TF_CURRENCYPACK_BLINK_PERIOD - RandomFloat( 0.0, TF_CURRENCYPACK_BLINK_DURATION ), "CurrencyPackWaitingToBlinkThink" );
// Force collision size to see if this fixes a bunch of stuck-in-geo issues goes away
SetCollisionBounds( Vector( -10, -10, -10 ), Vector( 10, 10, 10 ) );
if ( m_bDistributed )
{
DispatchParticleEffect( "mvm_cash_embers_red", PATTACH_ABSORIGIN_FOLLOW, this );
}
else
{
DispatchParticleEffect( "mvm_cash_embers", PATTACH_ABSORIGIN_FOLLOW, this );
}
// Store when this drops for time-based accounting - like with wave collection bonus
m_nWaveNumber = MannVsMachineStats_GetCurrentWave();
// if m_nAmount != 0, we already call SetAmount
m_nAmount = m_nAmount == 0 ? TFGameRules()->CalculateCurrencyAmount_ByType( GetPackSize() ) : m_nAmount;
MannVsMachineStats_RoundEvent_CreditsDropped( m_nWaveNumber, m_nAmount );
if ( !m_bDistributed && TFObjectiveResource() )
{
TFObjectiveResource()->AddMvMWorldMoney( m_nAmount );
}
}
//-----------------------------------------------------------------------------
// Purpose: Blink off/on when about to expire and play expire sound
//-----------------------------------------------------------------------------
void CCurrencyPack::BlinkThink( void )
{
// This means the pack was claimed by a player via Radius Currency Collection and
// is likely flying toward them. Regardless, one second later it fires Touch().
if ( IsClaimed() )
return;
++m_blinkCount;
SetRenderMode( kRenderTransAlpha );
if ( m_blinkCount & 0x1 )
{
SetRenderColorA( 25 );
}
else
{
SetRenderColorA( 255 );
}
SetContextThink( &CCurrencyPack::BlinkThink, gpGlobals->curtime + TF_CURRENCYPACK_BLINK_DURATION, "CurrencyPackBlinkThink" );
}
//-----------------------------------------------------------------------------
// Become touchable when we are at rest
//-----------------------------------------------------------------------------
void CCurrencyPack::ComeToRest( void )
{
BaseClass::ComeToRest();
if ( IsClaimed() || m_bDistributed )
return;
// if we've come to rest in an area with no nav, just grant the money to the player
if ( TheNavMesh->GetNavArea( GetAbsOrigin() ) == NULL )
{
TFGameRules()->DistributeCurrencyAmount( m_nAmount );
m_bTouched = true;
UTIL_Remove( this );
return;
}
// See if we've come to rest in a trigger_hurt
for ( int i = 0; i < ITriggerHurtAutoList::AutoList().Count(); i++ )
{
CTriggerHurt *pTrigger = static_cast<CTriggerHurt*>( ITriggerHurtAutoList::AutoList()[i] );
if ( !pTrigger->m_bDisabled )
{
Vector vecMins, vecMaxs;
pTrigger->GetCollideable()->WorldSpaceSurroundingBounds( &vecMins, &vecMaxs );
if ( IsPointInBox( GetCollideable()->GetCollisionOrigin(), vecMins, vecMaxs ) )
{
TFGameRules()->DistributeCurrencyAmount( m_nAmount );
m_bTouched = true;
UTIL_Remove( this );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the value of a custom pack
//-----------------------------------------------------------------------------
void CCurrencyPack::SetAmount( float nAmount )
{
Assert( GetPackSize() == TF_CURRENCY_PACK_CUSTOM ); // Never set an amount unless we're custom
m_nAmount = nAmount;
}
//-----------------------------------------------------------------------------
// Purpose: Distribute the money right away
//-----------------------------------------------------------------------------
void CCurrencyPack::DistributedBy( CBasePlayer* pMoneyMaker )
{
TFGameRules()->DistributeCurrencyAmount( m_nAmount );
if ( pMoneyMaker )
{
CTF_GameStats.Event_PlayerCollectedCurrency( pMoneyMaker, m_nAmount );
}
m_bDistributed = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCurrencyPack::Precache( void )
{
PrecacheScriptSound( TF_CURRENCYPACK_PICKUP_SOUND );
PrecacheScriptSound( TF_CURRENCYPACK_VANISH_SOUND );
PrecacheParticleSystem( "mvm_cash_embers" );
PrecacheParticleSystem( "mvm_cash_explosion" );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CCurrencyPack::MyTouch( CBasePlayer *pPlayer )
{
if ( ValidTouch( pPlayer ) && !m_bTouched )
{
CTFPlayer *pTFTouchPlayer = ToTFPlayer( pPlayer );
if ( !pTFTouchPlayer )
return false;
if ( pTFTouchPlayer->IsBot() )
return false;
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
{
// Prevent losing team from grabbing money - screws up stats in checkpoints
if ( TFGameRules()->State_Get() == GR_STATE_TEAM_WIN )
{
if ( TFGameRules()->GetWinningTeam() != pTFTouchPlayer->GetTeamNumber() )
return false;
}
// Scouts gain health when grabbing currency packs
if ( pTFTouchPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_SCOUT )
{
const int nCurHealth = pTFTouchPlayer->GetHealth();
const int nMaxHealth = pTFTouchPlayer->GetMaxHealth();
int nHealth = nCurHealth < nMaxHealth ? 50 : 25;
// If we cross the border into insanity, scale the reward
const int nHealthCap = nMaxHealth * 4;
if ( nCurHealth > nHealthCap )
{
nHealth = RemapValClamped( nCurHealth, nHealthCap, (nHealthCap * 1.5f), 20, 5 );
}
pTFTouchPlayer->TakeHealth( nHealth, DMG_IGNORE_MAXHEALTH );
}
MannVsMachineStats_PlayerEvent_PickedUpCredits( pTFTouchPlayer, m_nWaveNumber, m_nAmount );
IGameEvent *event = gameeventmanager->CreateEvent( "mvm_pickup_currency" );
if ( event )
{
event->SetInt( "player", pTFTouchPlayer->entindex() );
event->SetInt( "currency", m_nAmount );
gameeventmanager->FireEvent( event );
}
// is the money blinking and about to burn up?
if ( m_blinkCount > 0 )
{
pTFTouchPlayer->AwardAchievement( ACHIEVEMENT_TF_MVM_PICKUP_MONEY_ABOUT_TO_EXPIRE );
}
}
CReliableBroadcastRecipientFilter filter;
EmitSound( filter, entindex(), TF_CURRENCYPACK_PICKUP_SOUND );
if ( !m_bDistributed )
{
TFGameRules()->DistributeCurrencyAmount( m_nAmount, pTFTouchPlayer );
CTF_GameStats.Event_PlayerCollectedCurrency( pTFTouchPlayer, m_nAmount );
}
if ( ( !pTFTouchPlayer->IsPlayerClass( TF_CLASS_SPY ) ) ||
( !pTFTouchPlayer->m_Shared.IsStealthed() && !pTFTouchPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) && !pTFTouchPlayer->m_Shared.InCond( TF_COND_DISGUISED ) ) )
{
pTFTouchPlayer->SpeakConceptIfAllowed( MP_CONCEPT_MVM_MONEY_PICKUP );
}
pTFTouchPlayer->SetLastObjectiveTime( gpGlobals->curtime );
m_bTouched = true;
}
return m_bTouched;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *CCurrencyPackCustom::GetDefaultPowerupModel( void )
{
// Custom packs should always be set to a value by hand
Assert( m_nAmount > 0 );
// Try to pick a model that's appropriate to our drop amount (which is in our multiplier)
if ( m_nAmount >= 25 )
return "models/items/currencypack_large.mdl";
if ( m_nAmount >= 10 )
return "models/items/currencypack_medium.mdl";
return "models/items/currencypack_small.mdl";
}