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

199 lines
5.5 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "passtime_ballcontroller_homing.h"
#include "passtime_convars.h"
#include "tf_passtime_logic.h"
#include "tf_passtime_ball.h"
#include "tf_weapon_passtime_gun.h"
#include "tf_gamestats.h"
#include "tf_gamerules.h"
#include "tf_player.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
CPasstimeBallControllerHoming::CPasstimeBallControllerHoming()
: CPasstimeBallController( 1 )
, m_fTargetSpeed( 0 )
, m_bIsHoming( false )
, m_fHomingStrength( 0 )
{}
//-----------------------------------------------------------------------------
CPasstimeBallControllerHoming::~CPasstimeBallControllerHoming()
{
StopHoming();
}
//-----------------------------------------------------------------------------
void CPasstimeBallControllerHoming::StartHoming( CPasstimeBall *pBall, CTFPlayer *pTarget, bool isCharged )
{
Assert( pTarget && pBall );
SetIsEnabled( true );
m_bIsHoming = true;
m_hTarget = pTarget;
m_hBall = pBall;
pBall->VPhysicsGetObject()->EnableGravity( false );
m_fHomingStrength = 0.01f; // totally arbitrary
pBall->SetHomingTarget( pTarget );
if ( tf_passtime_experiment_instapass.GetBool() && (!tf_passtime_experiment_instapass_charge.GetBool() || isCharged) )
{
auto pos = pTarget->EyePosition();
pBall->Teleport( &pos, nullptr, nullptr );
}
}
//-----------------------------------------------------------------------------
void CPasstimeBallControllerHoming::StopHoming()
{
if ( !m_bIsHoming )
return;
CPasstimeBall *pBall = m_hBall.Get();
if ( pBall )
{
if( pBall->VPhysicsGetObject() )
{
pBall->VPhysicsGetObject()->EnableGravity( true );
}
pBall->SetHomingTarget( 0 );
}
m_bIsHoming = false;
m_hTarget = 0;
m_hBall = 0;
}
//-----------------------------------------------------------------------------
void CPasstimeBallControllerHoming::SetTargetSpeed( float f )
{
m_fTargetSpeed = MAX(1.0f, f);
}
//-----------------------------------------------------------------------------
bool CPasstimeBallControllerHoming::IsActive() const
{
return m_bIsHoming;
}
//-----------------------------------------------------------------------------
bool CPasstimeBallControllerHoming::Apply( CPasstimeBall *ball )
{
if ( ball != m_hBall )
return false;
if ( !m_hBall.Get() )
{
StopHoming();
return false;
}
CTFPlayer *pPlayer = m_hTarget.Get();
if( !pPlayer )
{
StopHoming();
return false;
}
HudNotification_t cantPickUpReason;
if ( pPlayer && !g_pPasstimeLogic->BCanPlayerPickUpBall( pPlayer, &cantPickUpReason ) )
{
if ( cantPickUpReason && TFGameRules() )
{
CSingleUserReliableRecipientFilter filter( pPlayer );
TFGameRules()->SendHudNotification( filter, cantPickUpReason );
}
if ( m_bIsHoming )
{
++CTF_GameStats.m_passtimeStats.summary.nTotalPassesFailed;
CTF_GameStats.m_passtimeStats.AddPassTravelDistSample( ball->GetAirtimeDistance() );
StopHoming();
}
return false;
}
Assert( IsActive() && IsEnabled() );
IPhysicsObject *pPhys = ball->VPhysicsGetObject();
Vector ballpos;
pPhys->GetPosition( &ballpos, 0 );
Vector targetvel = pPlayer->EyePosition() - ballpos;
targetvel.NormalizeInPlace();
targetvel *= m_fTargetSpeed;
Vector currentvel;
pPhys->GetVelocity( &currentvel, 0 );
Vector steer = targetvel - currentvel;
pPhys->ApplyForceCenter( steer * m_fHomingStrength );
m_fHomingStrength = clamp(m_fHomingStrength * 1.1f, 0, 1); // totally arbitrary
return true;
}
//-----------------------------------------------------------------------------
void CPasstimeBallControllerHoming::OnBallCollision(
CPasstimeBall *ball, int index, gamevcollisionevent_t *ev )
{
Assert( IsActive() && IsEnabled() );
if ( ball != m_hBall )
return;
if ( m_iMaxBounces <= 0 )
{
if ( m_bIsHoming )
{
++CTF_GameStats.m_passtimeStats.summary.nTotalPassesFailed;
CTF_GameStats.m_passtimeStats.AddPassTravelDistSample( ball->GetAirtimeDistance() );
StopHoming();
}
}
else
--m_iMaxBounces;
}
//-----------------------------------------------------------------------------
void CPasstimeBallControllerHoming::OnBallPickedUp(
CPasstimeBall *ball, CTFPlayer *catcher )
{
Assert( IsActive() && IsEnabled() );
if ( ball == m_hBall )
StopHoming();
}
//-----------------------------------------------------------------------------
void CPasstimeBallControllerHoming::OnBallDamaged( CPasstimeBall *ball )
{
Assert( IsActive() && IsEnabled() );
if ( ball == m_hBall && m_bIsHoming )
{
++CTF_GameStats.m_passtimeStats.summary.nTotalPassesShotDown;
++CTF_GameStats.m_passtimeStats.summary.nTotalPassesFailed;
CTF_GameStats.m_passtimeStats.AddPassTravelDistSample( ball->GetAirtimeDistance() );
StopHoming();
}
}
//-----------------------------------------------------------------------------
void CPasstimeBallControllerHoming::OnBallSpawned( CPasstimeBall *ball )
{
Assert( IsActive() && IsEnabled() );
StopHoming();
}
//-----------------------------------------------------------------------------
void CPasstimeBallControllerHoming::OnDisabled()
{
if ( m_bIsHoming )
{
++CTF_GameStats.m_passtimeStats.summary.nTotalPassesShotDown;
++CTF_GameStats.m_passtimeStats.summary.nTotalPassesFailed;
CTF_GameStats.m_passtimeStats.AddPassTravelDistSample( m_hBall->GetAirtimeDistance() );
}
StopHoming();
}