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