You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
393 lines
12 KiB
393 lines
12 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose: Client's CObjectSentrygun
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================//
|
||
|
#include "cbase.h"
|
||
|
#include "c_baseobject.h"
|
||
|
#include "c_tf_player.h"
|
||
|
#include "vgui/ILocalize.h"
|
||
|
#include "c_obj_dispenser.h"
|
||
|
|
||
|
// NVNT haptics system interface
|
||
|
#include "c_tf_haptics.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include "tier0/memdbgon.h"
|
||
|
|
||
|
using namespace vgui;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: RecvProxy that converts the Team's player UtlVector to entindexes
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void RecvProxy_HealingList( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||
|
{
|
||
|
C_ObjectDispenser *pDispenser = (C_ObjectDispenser*)pStruct;
|
||
|
|
||
|
CBaseHandle *pHandle = (CBaseHandle*)(&(pDispenser->m_hHealingTargets[pData->m_iElement]));
|
||
|
RecvProxy_IntToEHandle( pData, pStruct, pHandle );
|
||
|
|
||
|
// update the heal beams
|
||
|
pDispenser->m_bUpdateHealingTargets = true;
|
||
|
}
|
||
|
|
||
|
void RecvProxyArrayLength_HealingArray( void *pStruct, int objectID, int currentArrayLength )
|
||
|
{
|
||
|
C_ObjectDispenser *pDispenser = (C_ObjectDispenser*)pStruct;
|
||
|
|
||
|
if ( pDispenser->m_hHealingTargets.Size() != currentArrayLength )
|
||
|
pDispenser->m_hHealingTargets.SetSize( currentArrayLength );
|
||
|
|
||
|
// update the heal beams
|
||
|
pDispenser->m_bUpdateHealingTargets = true;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Dispenser object
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
IMPLEMENT_CLIENTCLASS_DT(C_ObjectDispenser, DT_ObjectDispenser, CObjectDispenser)
|
||
|
RecvPropInt( RECVINFO( m_iState ) ),
|
||
|
RecvPropInt( RECVINFO( m_iAmmoMetal ) ),
|
||
|
RecvPropInt( RECVINFO( m_iMiniBombCounter ) ),
|
||
|
|
||
|
RecvPropArray2(
|
||
|
RecvProxyArrayLength_HealingArray,
|
||
|
RecvPropInt( "healing_array_element", 0, SIZEOF_IGNORE, 0, RecvProxy_HealingList ),
|
||
|
MAX_PLAYERS,
|
||
|
0,
|
||
|
"healing_array"
|
||
|
)
|
||
|
END_RECV_TABLE()
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
C_ObjectDispenser::C_ObjectDispenser()
|
||
|
{
|
||
|
m_bUpdateHealingTargets = false;
|
||
|
m_bPlayingSound = false;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
C_ObjectDispenser::~C_ObjectDispenser()
|
||
|
{
|
||
|
StopSound( "Building_Dispenser.Heal" );
|
||
|
// NVNT see if local player is in the list of targets
|
||
|
// temp. fix if dispener is destroyed will stop all healers.
|
||
|
if(m_bPlayingSound)
|
||
|
{
|
||
|
if(tfHaptics.healingDispenserCount>0) {
|
||
|
tfHaptics.healingDispenserCount --;
|
||
|
if(tfHaptics.healingDispenserCount==0 && !tfHaptics.wasBeingHealedMedic)
|
||
|
tfHaptics.isBeingHealed = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : updateType -
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void C_ObjectDispenser::OnDataChanged( DataUpdateType_t updateType )
|
||
|
{
|
||
|
BaseClass::OnDataChanged( updateType );
|
||
|
|
||
|
#ifdef STAGING_ONLY
|
||
|
if ( updateType == DATA_UPDATE_CREATED )
|
||
|
{
|
||
|
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||
|
}
|
||
|
#endif // STAGING_ONLY
|
||
|
|
||
|
if ( m_bUpdateHealingTargets )
|
||
|
{
|
||
|
UpdateEffects();
|
||
|
m_bUpdateHealingTargets = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void C_ObjectDispenser::ClientThink()
|
||
|
{
|
||
|
BaseClass::ClientThink();
|
||
|
|
||
|
#ifdef STAGING_ONLY
|
||
|
C_TFPlayer *pTFOwner = GetOwner();
|
||
|
if ( pTFOwner && pTFOwner->m_Shared.IsEnteringOrExitingFullyInvisible() )
|
||
|
{
|
||
|
UpdateEffects();
|
||
|
}
|
||
|
#endif // STAGING_ONLY
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void C_ObjectDispenser::SetInvisibilityLevel( float flValue )
|
||
|
{
|
||
|
if ( IsEnteringOrExitingFullyInvisible( flValue ) )
|
||
|
{
|
||
|
UpdateEffects();
|
||
|
}
|
||
|
|
||
|
BaseClass::SetInvisibilityLevel( flValue );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void C_ObjectDispenser::UpdateEffects( void )
|
||
|
{
|
||
|
C_TFPlayer *pOwner = GetOwner();
|
||
|
|
||
|
if ( GetInvisibilityLevel() == 1.f || ( pOwner && pOwner->m_Shared.IsFullyInvisible() ) )
|
||
|
{
|
||
|
StopEffects( true );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
StopEffects();
|
||
|
|
||
|
// Now add any new targets
|
||
|
for ( int i = 0; i < m_hHealingTargets.Count(); i++ )
|
||
|
{
|
||
|
C_BaseEntity *pTarget = m_hHealingTargets[i].Get();
|
||
|
|
||
|
// Loops through the healing targets, and make sure we have an effect for each of them
|
||
|
if ( pTarget )
|
||
|
{
|
||
|
// don't want to show this effect for stealthed spies
|
||
|
C_TFPlayer *pPlayer = dynamic_cast< C_TFPlayer * >( pTarget );
|
||
|
if ( pPlayer && ( pPlayer->m_Shared.IsStealthed() || pPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) ) )
|
||
|
continue;
|
||
|
|
||
|
bool bHaveEffect = false;
|
||
|
for ( int targets = 0; targets < m_hHealingTargetEffects.Count(); targets++ )
|
||
|
{
|
||
|
if ( m_hHealingTargetEffects[targets].pTarget == pTarget )
|
||
|
{
|
||
|
bHaveEffect = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( bHaveEffect )
|
||
|
continue;
|
||
|
// NVNT if the dispenser has started to heal the local player
|
||
|
// notify the haptics system
|
||
|
if(pTarget==C_BasePlayer::GetLocalPlayer())
|
||
|
{
|
||
|
tfHaptics.healingDispenserCount++;
|
||
|
if(!tfHaptics.wasBeingHealedMedic) {
|
||
|
tfHaptics.isBeingHealed = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char *pszEffectName;
|
||
|
if ( GetTeamNumber() == TF_TEAM_RED )
|
||
|
{
|
||
|
pszEffectName = "dispenser_heal_red";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszEffectName = "dispenser_heal_blue";
|
||
|
}
|
||
|
|
||
|
CNewParticleEffect *pEffect;
|
||
|
|
||
|
// if we don't have a model, attach at the origin, otherwise use attachment 'heal_origin'
|
||
|
if ( FBitSet( GetObjectFlags(), OF_DOESNT_HAVE_A_MODEL ) )
|
||
|
{
|
||
|
// offset the origin to player's chest
|
||
|
if ( FBitSet( GetObjectFlags(), OF_PLAYER_DESTRUCTION ) )
|
||
|
{
|
||
|
pEffect = ParticleProp()->Create( pszEffectName, PATTACH_ABSORIGIN_FOLLOW, NULL, Vector( 0, 0, 50 ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pEffect = ParticleProp()->Create( pszEffectName, PATTACH_ABSORIGIN_FOLLOW );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pEffect = ParticleProp()->Create( pszEffectName, PATTACH_POINT_FOLLOW, "heal_origin" );
|
||
|
}
|
||
|
|
||
|
ParticleProp()->AddControlPoint( pEffect, 1, pTarget, PATTACH_ABSORIGIN_FOLLOW, NULL, Vector(0,0,50) );
|
||
|
|
||
|
int iIndex = m_hHealingTargetEffects.AddToTail();
|
||
|
m_hHealingTargetEffects[iIndex].pTarget = pTarget;
|
||
|
m_hHealingTargetEffects[iIndex].pEffect = pEffect;
|
||
|
|
||
|
// Start the sound over again every time we start a new beam
|
||
|
StopSound( "Building_Dispenser.Heal" );
|
||
|
|
||
|
CLocalPlayerFilter filter;
|
||
|
EmitSound( filter, entindex(), "Building_Dispenser.Heal" );
|
||
|
|
||
|
m_bPlayingSound = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Stop the sound if we're not healing anyone
|
||
|
if ( m_bPlayingSound && m_hHealingTargets.Count() == 0 )
|
||
|
{
|
||
|
m_bPlayingSound = false;
|
||
|
|
||
|
// stop the sound
|
||
|
StopSound( "Building_Dispenser.Heal" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void C_ObjectDispenser::StopEffects( bool bRemoveAll /* = false */ )
|
||
|
{
|
||
|
// Find all the targets we've stopped healing
|
||
|
bool bStillHealing[MAX_DISPENSER_HEALING_TARGETS] = { 0 };
|
||
|
for ( int i = 0; i < m_hHealingTargetEffects.Count(); i++ )
|
||
|
{
|
||
|
bStillHealing[i] = false;
|
||
|
|
||
|
// Are we still healing this target?
|
||
|
if ( !bRemoveAll )
|
||
|
{
|
||
|
for ( int target = 0; target < m_hHealingTargets.Count(); target++ )
|
||
|
{
|
||
|
if ( m_hHealingTargets[target] && m_hHealingTargets[target] == m_hHealingTargetEffects[i].pTarget )
|
||
|
{
|
||
|
bStillHealing[i] = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now remove all the dead effects
|
||
|
for ( int i = m_hHealingTargetEffects.Count()-1; i >= 0; i-- )
|
||
|
{
|
||
|
if ( !bStillHealing[i] )
|
||
|
{
|
||
|
|
||
|
// NVNT if the healing target of this dispenser is the local player.
|
||
|
// inform the haptics system interface we are no longer healing.
|
||
|
if(m_hHealingTargetEffects[i].pTarget==C_BasePlayer::GetLocalPlayer())
|
||
|
{
|
||
|
if(tfHaptics.healingDispenserCount>0) {
|
||
|
tfHaptics.healingDispenserCount --;
|
||
|
if(tfHaptics.healingDispenserCount==0 && !tfHaptics.wasBeingHealedMedic)
|
||
|
tfHaptics.isBeingHealed = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ParticleProp()->StopEmission( m_hHealingTargetEffects[i].pEffect );
|
||
|
m_hHealingTargetEffects.Remove(i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Damage level has changed, update our effects
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void C_ObjectDispenser::UpdateDamageEffects( BuildingDamageLevel_t damageLevel )
|
||
|
{
|
||
|
if ( m_hDamageEffects )
|
||
|
{
|
||
|
m_hDamageEffects->StopEmission( false, false );
|
||
|
m_hDamageEffects = NULL;
|
||
|
}
|
||
|
|
||
|
const char *pszEffect = "";
|
||
|
|
||
|
switch( damageLevel )
|
||
|
{
|
||
|
case BUILDING_DAMAGE_LEVEL_LIGHT:
|
||
|
pszEffect = "dispenserdamage_1";
|
||
|
break;
|
||
|
case BUILDING_DAMAGE_LEVEL_MEDIUM:
|
||
|
pszEffect = "dispenserdamage_2";
|
||
|
break;
|
||
|
case BUILDING_DAMAGE_LEVEL_HEAVY:
|
||
|
pszEffect = "dispenserdamage_3";
|
||
|
break;
|
||
|
case BUILDING_DAMAGE_LEVEL_CRITICAL:
|
||
|
pszEffect = "dispenserdamage_4";
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( Q_strlen(pszEffect) > 0 )
|
||
|
{
|
||
|
m_hDamageEffects = ParticleProp()->Create( pszEffect, PATTACH_ABSORIGIN );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int C_ObjectDispenser::GetMaxMetal( void )
|
||
|
{
|
||
|
return DISPENSER_MAX_METAL_AMMO;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Control screen
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
DECLARE_VGUI_SCREEN_FACTORY( CDispenserControlPanel, "screen_obj_dispenser_blue" );
|
||
|
DECLARE_VGUI_SCREEN_FACTORY( CDispenserControlPanel_Red, "screen_obj_dispenser_red" );
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Constructor:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CDispenserControlPanel::CDispenserControlPanel( vgui::Panel *parent, const char *panelName )
|
||
|
: BaseClass( parent, "CDispenserControlPanel" )
|
||
|
{
|
||
|
m_pAmmoProgress = new RotatingProgressBar( this, "MeterArrow" );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Deactivates buttons we can't afford
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CDispenserControlPanel::OnTickActive( C_BaseObject *pObj, C_TFPlayer *pLocalPlayer )
|
||
|
{
|
||
|
BaseClass::OnTickActive( pObj, pLocalPlayer );
|
||
|
|
||
|
Assert( dynamic_cast< C_ObjectDispenser* >( pObj ) );
|
||
|
m_hDispenser = static_cast< C_ObjectDispenser* >( pObj );
|
||
|
|
||
|
float flProgress = m_hDispenser ? m_hDispenser->GetMetalAmmoCount() / (float)m_hDispenser->GetMaxMetal() : 0.f;
|
||
|
|
||
|
m_pAmmoProgress->SetProgress( flProgress );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CDispenserControlPanel::IsVisible( void )
|
||
|
{
|
||
|
if ( m_hDispenser )
|
||
|
{
|
||
|
#ifdef STAGING_ONLY
|
||
|
if ( m_hDispenser->IsMiniBuilding() )
|
||
|
return false;
|
||
|
#endif // STAGING_ONLY
|
||
|
|
||
|
if ( m_hDispenser->GetInvisibilityLevel() == 1.f )
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return BaseClass::IsVisible();
|
||
|
}
|
||
|
|
||
|
IMPLEMENT_CLIENTCLASS_DT(C_ObjectCartDispenser, DT_ObjectCartDispenser, CObjectCartDispenser)
|
||
|
END_RECV_TABLE()
|