summaryrefslogtreecommitdiff
path: root/game/client/tf/c_obj_dispenser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf/c_obj_dispenser.cpp')
-rw-r--r--game/client/tf/c_obj_dispenser.cpp393
1 files changed, 393 insertions, 0 deletions
diff --git a/game/client/tf/c_obj_dispenser.cpp b/game/client/tf/c_obj_dispenser.cpp
new file mode 100644
index 0000000..169aa58
--- /dev/null
+++ b/game/client/tf/c_obj_dispenser.cpp
@@ -0,0 +1,393 @@
+//========= 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() \ No newline at end of file