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
//========= 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() |