//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Client's CObjectSentrygun
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_tf_player.h"
#include "vgui_bitmapbutton.h"
#include "vgui/ILocalize.h"
#include "tf_fx_muzzleflash.h"
#include "eventlist.h"
#include "hintsystem.h"
#include <vgui_controls/ProgressBar.h>
#include "igameevents.h"

#include "c_obj_sentrygun.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

using namespace vgui;

static void RecvProxy_BooleanToShieldLevel( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
	// convert old boolean "m_bShielded" to uint32 "m_nShieldLevel"
	*(uint32*)pOut = ( pData->m_Value.m_Int != 0 ) ? 1 : 0;
}

IMPLEMENT_NETWORKCLASS_ALIASED( TFProjectile_SentryRocket, DT_TFProjectile_SentryRocket )

BEGIN_NETWORK_TABLE( C_TFProjectile_SentryRocket, DT_TFProjectile_SentryRocket )
END_NETWORK_TABLE()

BEGIN_NETWORK_TABLE_NOBASE( C_ObjectSentrygun, DT_SentrygunLocalData )
	RecvPropInt( RECVINFO(m_iKills) ),
	RecvPropInt( RECVINFO(m_iAssists) ),
END_NETWORK_TABLE()

IMPLEMENT_CLIENTCLASS_DT(C_ObjectSentrygun, DT_ObjectSentrygun, CObjectSentrygun)
	RecvPropInt( RECVINFO(m_iAmmoShells) ),
	RecvPropInt( RECVINFO(m_iAmmoRockets) ),
	RecvPropInt( RECVINFO(m_iState) ),
	RecvPropBool( RECVINFO(m_bPlayerControlled) ),
	RecvPropInt( RECVINFO(m_nShieldLevel) ),
	RecvPropInt( RECVINFO_NAME(m_nShieldLevel, m_bShielded), 0, RecvProxy_BooleanToShieldLevel ), // for demo compatibility only
	RecvPropEHandle( RECVINFO( m_hEnemy ) ),
	RecvPropEHandle( RECVINFO( m_hAutoAimTarget ) ),
	RecvPropDataTable( "SentrygunLocalData", 0, 0, &REFERENCE_RECV_TABLE( DT_SentrygunLocalData ) ),
END_RECV_TABLE()

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
C_ObjectSentrygun::C_ObjectSentrygun()
{
	m_iMaxAmmoShells = SENTRYGUN_MAX_SHELLS_1;
	m_bPlayerControlled = false;
	m_bOldPlayerControlled = false;
	m_nShieldLevel = SHIELD_NONE;
	m_nOldShieldLevel = SHIELD_NONE;
	m_hLaserBeamEffect = NULL;
	m_pTempShield = NULL;
	m_bNearMiss = false;
	m_flNextNearMissCheck = 0.f;

	m_iOldModelIndex = 0;
	m_bOldCarried = false;
	m_bRecreateShield = false;
	m_bRecreateLaserBeam = false;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::UpdateOnRemove( void )
{
	DestroyLaserBeam();
	DestroyShield();
	DestroySiren();

	BaseClass::UpdateOnRemove();
}


void C_ObjectSentrygun::GetAmmoCount( int &iShells, int &iMaxShells, int &iRockets, int & iMaxRockets )
{
	iShells = m_iAmmoShells;
	iMaxShells = m_iMaxAmmoShells;
	iRockets = m_iAmmoRockets;
	iMaxRockets = SENTRYGUN_MAX_ROCKETS;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::UpgradeLevelChanged()
{
	switch( m_iUpgradeLevel )
	{
	case 1:	
		{ 
			VectorCopy( SENTRYGUN_EYE_OFFSET_LEVEL_1, m_vecViewOffset );
			m_iMaxAmmoShells = SENTRYGUN_MAX_SHELLS_1;
			break;
		}
	case 2:	
		{ 
			VectorCopy( SENTRYGUN_EYE_OFFSET_LEVEL_2, m_vecViewOffset );
			m_iMaxAmmoShells = SENTRYGUN_MAX_SHELLS_2;
			break;
		}
	case 3:	
		{ 
			VectorCopy( SENTRYGUN_EYE_OFFSET_LEVEL_3, m_vecViewOffset );
			m_iMaxAmmoShells = SENTRYGUN_MAX_SHELLS_3;
			break;
		}
	default: 
		{ 
			Assert( 0 ); 
			break;
		}
	}

	CreateLaserBeam();

	// Because the bounding box size changes when upgrading, force the shadow to be reprojected using the new bounds
	g_pClientShadowMgr->AddToDirtyShadowList( this, true );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::OnPreDataChanged( DataUpdateType_t updateType )
{
	BaseClass::OnPreDataChanged( updateType );

	m_iOldBodygroups = GetBody();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::OnDataChanged( DataUpdateType_t updateType )
{
	BaseClass::OnDataChanged( updateType );

	// intercept bodygroup sets from the server
	// we aren't clientsideanimating, but we don't want the server setting our
	// bodygroup while we are placing
	if ( m_iOldBodygroups != GetBody() )
	{
		if ( IsPlacing() )
		{
			m_nBody = m_iOldBodygroups;
		}
	}

	if ( GetModelIndex() != m_iOldModelIndex )
	{
		m_iOldModelIndex = GetModelIndex();

		if ( IsMiniBuilding() )
		{
			CStudioHdr *pStudiohdr = GetModelPtr();
			int bodyGroup = FindBodygroupByName( "mini_sentry_light" );
			if ( bodyGroup < pStudiohdr->numbodyparts() )
			{
				mstudiobodyparts_t *pbodypart = pStudiohdr->pBodypart( bodyGroup );
				if ( pbodypart->base > 0 )
				{
					SetBodygroup( bodyGroup, 1 );
				}
			}
		}
	}

	if ( m_bPlayerControlled != m_bOldPlayerControlled || m_bRecreateLaserBeam )
	{
		if ( m_bPlayerControlled )
		{
			CreateLaserBeam();
		}
		else
		{
			DestroyLaserBeam();
		}
		m_bOldPlayerControlled = m_bPlayerControlled;
		m_bRecreateLaserBeam = false;
	}

	if ( m_nShieldLevel != m_nOldShieldLevel || m_bRecreateShield )
	{
		if ( m_nShieldLevel > 0 )
		{
			CreateShield();
		}
		else
		{
			DestroyShield();
		}
		m_nOldShieldLevel = m_nShieldLevel;
		m_bRecreateShield = false;
	}

	if ( IsCarried() != m_bOldCarried )
	{
		m_bOldCarried = IsCarried();
		if ( IsCarried() )
		{
			DestroySiren();
		}
	}

	if ( ShouldBeActive() && !IsDisabled() && IsMiniBuilding() && !m_hSirenEffect )
	{
		CreateSiren();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::OnGoActive( void )
{
	CreateSiren();

	BaseClass::OnGoActive();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::OnGoInactive( void )
{
	DestroySiren();

	BaseClass::OnGoInactive();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::OnStartDisabled( void )
{
	DestroySiren();

	BaseClass::OnStartDisabled();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::OnEndDisabled( void )
{
	CreateSiren();

	BaseClass::OnEndDisabled();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::CreateLaserBeam( void )
{
	if ( !m_bPlayerControlled )
		return;

	DestroyLaserBeam();

	int iAttachment = LookupAttachment( "laser_origin" );
	m_hLaserBeamEffect = ParticleProp()->Create( "laser_sight_beam", PATTACH_POINT_FOLLOW, iAttachment );
	if ( m_hLaserBeamEffect )
	{
		m_hLaserBeamEffect->SetSortOrigin( m_hLaserBeamEffect->GetRenderOrigin() );
	}

	SetNextClientThink( CLIENT_THINK_ALWAYS );

	if ( m_hLaserBeamEffect )
	{
		if ( GetTeamNumber() == TF_TEAM_BLUE )
		{
			m_hLaserBeamEffect->SetControlPoint( 2, Vector( 0, 0, 255 ) );
		}
		else
		{
			m_hLaserBeamEffect->SetControlPoint( 2, Vector( 255, 0, 0 ) );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::DestroyLaserBeam( void )
{
	if ( m_hLaserBeamEffect )
	{
		SetNextClientThink( CLIENT_THINK_NEVER );
		ParticleProp()->StopEmissionAndDestroyImmediately( m_hLaserBeamEffect );
		m_hLaserBeamEffect = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::SetDormant( bool bDormant )
{
	if ( IsDormant() && !bDormant )
	{
		// Make sure our shield is where we are. We may have moved since last seen.
		if ( m_pTempShield )
		{
			m_bRecreateShield = true;
			m_bRecreateLaserBeam = true;
		}
	}

	BaseClass::SetDormant( bDormant );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::CreateShield( void )
{
	DestroyShield();

	model_t *pModel = (model_t *) engine->LoadModel( "models/buildables/sentry_shield.mdl" );
	m_pTempShield = tempents->SpawnTempModel( pModel, GetAbsOrigin(), GetAbsAngles(), Vector(0, 0, 0), 1, FTENT_NEVERDIE );
	if ( m_pTempShield )
	{
		m_pTempShield->ChangeTeam( GetTeamNumber() );
		m_pTempShield->m_nSkin = ( GetTeamNumber() == TF_TEAM_RED ) ? 0 : 1;
		//m_pTempShield->m_nRenderFX = kRenderFxDistort;
	}

	m_hShieldEffect = ParticleProp()->Create( "turret_shield", PATTACH_ABSORIGIN_FOLLOW, 0, Vector( 0,0,30) );
	if ( !m_hShieldEffect )
		return;
	if ( GetTeamNumber() == TF_TEAM_BLUE )
	{
		m_hShieldEffect->SetControlPoint( 1, Vector(50,150,255) );
	}
	else
	{
		m_hShieldEffect->SetControlPoint( 1, Vector(255,50,50) );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::DestroyShield( void )
{
	if ( m_pTempShield )
	{
		m_pTempShield->flags = FTENT_FADEOUT;
		m_pTempShield->die = gpGlobals->curtime;
		m_pTempShield->fadeSpeed = 1.0f;
		m_pTempShield = NULL;
	}

	if ( m_hShieldEffect )
	{
		ParticleProp()->StopEmission( m_hShieldEffect );
		m_hShieldEffect = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::CreateSiren( void )
{
	if ( !IsMiniBuilding() )
		return;

	if ( IsCarried() )
		return;

	if ( m_hSirenEffect )
		return;

	const char* flashlightName = "cart_flashinglight";
	if ( GetTeamNumber() == TF_TEAM_RED )
	{
		flashlightName = "cart_flashinglight_red";
	}
	m_hSirenEffect = ParticleProp()->Create( flashlightName, PATTACH_POINT_FOLLOW, "siren" );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::DestroySiren( void )
{
	if ( m_hSirenEffect )
	{
		ParticleProp()->StopEmission( m_hSirenEffect );
		m_hSirenEffect = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::ClientThink( void )
{
	if ( m_hLaserBeamEffect && m_hEnemy && GetBuilder() )
	{
		QAngle vecAngles;
		Vector vecMuzzleOrigin;
		int iAttachment = 0;
		switch ( GetUpgradeLevel() )
		{
		case 1:
			iAttachment = LookupAttachment( "muzzle" );
			break;
		case 2:
			iAttachment = LookupAttachment( "muzzle_l" );
			break;
		case 3:
			iAttachment = LookupAttachment( "rocket_l" );
			break;
		}
		GetAttachment( iAttachment, vecMuzzleOrigin, vecAngles );

		Vector vForward;
		AngleVectors( vecAngles, &vForward );

		Vector vEnd = m_hEnemy->WorldSpaceCenter();
		if ( m_hAutoAimTarget )
		{
			vEnd = m_hAutoAimTarget->GetAbsOrigin() + m_hAutoAimTarget->GetClassEyeHeight()*0.75f;
		}

		trace_t	trace;
		CTraceFilterIgnoreTeammatesAndTeamObjects filter( GetBuilder(), COLLISION_GROUP_NONE, GetBuilder()->GetTeamNumber() );
		UTIL_TraceLine( vecMuzzleOrigin, vEnd, MASK_SOLID, &filter, &trace );

		Vector vecInterpBeamPos;
		InterpolateVector( gpGlobals->frametime * 25.f, m_vecLaserBeamPos, trace.endpos, vecInterpBeamPos );

		m_hLaserBeamEffect->SetControlPoint( 1, vecInterpBeamPos );
		m_vecLaserBeamPos = vecInterpBeamPos;

		// Perform a near-miss check.
		// This works pretty well as a threat indicator for the arrow, let's try it for our laser.
		if ( gpGlobals->curtime > m_flNextNearMissCheck )
		{
//			CheckNearMiss( vecMuzzleOrigin, m_hEnemy->GetAbsOrigin() );
			m_flNextNearMissCheck = gpGlobals->curtime + 0.2f;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::CheckNearMiss( Vector vecStart, Vector vecEnd )
{
	// Check against the local player. If the laser sweeps near him, play the near miss sound...
	C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
	if ( !pLocalPlayer || !pLocalPlayer->IsAlive() )
		return;

	// Can't hear near miss sounds from friendly guns.
//	if ( pLocalPlayer->GetTeamNumber() == GetTeamNumber() )
//		return;

	Vector vecPlayerPos = pLocalPlayer->GetAbsOrigin();
	Vector vecClosestPoint;
	float dist;
	CalcClosestPointOnLineSegment( vecPlayerPos, vecStart, vecEnd, vecClosestPoint, &dist );
	dist = vecPlayerPos.DistTo( vecClosestPoint );
	if ( dist > 120 )
	{
		StopSound( "Building_Sentrygun.ShaftLaserPass" );
		return;
	}

	if ( !m_bNearMiss )
	{
		// We're good for a near miss!
		float soundlen = 0;
		EmitSound_t params;
		params.m_flSoundTime = 0;
		params.m_pSoundName = "Building_Sentrygun.ShaftLaserPass";
		params.m_pflSoundDuration = &soundlen;
		params.m_flVolume = 1.f - (dist / 120.f);
		CSingleUserRecipientFilter localFilter( pLocalPlayer );
		EmitSound( localFilter, pLocalPlayer->entindex(), params );

		m_bNearMiss = true;
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::DisplayHintTo( C_BasePlayer *pPlayer )
{
	bool bHintPlayed = false;

	C_TFPlayer *pTFPlayer = ToTFPlayer(pPlayer);
	if ( InSameTeam( pPlayer ) )
	{
		// We're looking at a friendly object. 
		if ( pTFPlayer->IsPlayerClass( TF_CLASS_ENGINEER ) )
		{
			// If the sentrygun can be upgraded, and I can afford it, let me know
			if ( GetHealth() == GetMaxHealth() && GetUpgradeLevel() < 3 )
			{
				if ( pTFPlayer->GetBuildResources() >= SENTRYGUN_UPGRADE_COST )
				{
					bHintPlayed = pTFPlayer->HintMessage( HINT_ENGINEER_UPGRADE_SENTRYGUN, false, true );
				}
				else
				{
					bHintPlayed = pTFPlayer->HintMessage( HINT_ENGINEER_METAL_TO_UPGRADE, false, true );
				}
			}
		}
	}

	if ( !bHintPlayed )
	{
		BaseClass::DisplayHintTo( pPlayer );
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *C_ObjectSentrygun::GetHudStatusIcon( void )
{
	const char *pszResult;

	switch( m_iUpgradeLevel )
	{
	case 1:
	default:
		pszResult = "obj_status_sentrygun_1";
		break;
	case 2:
		pszResult = "obj_status_sentrygun_2";
		break;
	case 3:
		pszResult = "obj_status_sentrygun_3";
		break;
	}

	return pszResult;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
BuildingHudAlert_t C_ObjectSentrygun::GetBuildingAlertLevel( void )
{
	BuildingHudAlert_t baseAlertLevel = BaseClass::GetBuildingAlertLevel();

	// Just warn on low shells.

	float flShellPercent = (float)m_iAmmoShells / (float)m_iMaxAmmoShells;

	BuildingHudAlert_t alertLevel = BUILDING_HUD_ALERT_NONE;

	if ( !IsCarried() )
	{
		if ( !IsBuilding() && flShellPercent < 0.25 )
		{
			alertLevel = BUILDING_HUD_ALERT_VERY_LOW_AMMO;
		}
		else if ( !IsBuilding() && flShellPercent < 0.50 )
		{
			alertLevel = BUILDING_HUD_ALERT_LOW_AMMO;
		}
	}

	return MAX( baseAlertLevel, alertLevel );
}

//-----------------------------------------------------------------------------
// Purpose: During placement, only use the smaller bbox for shadow calc, don't include the range bodygroup
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType )
{
	if ( IsPlacing() )
	{
		mins = CollisionProp()->OBBMins();
		maxs = CollisionProp()->OBBMaxs();

		// HACK: The collision prop bounding box doesn't quite cover the blueprint model, so we bloat it a little
		Vector bbBloat( 10.0f, 10.0f, 0.0f );
		mins -= bbBloat;
		maxs += bbBloat;
	}
	else
	{
		BaseClass::GetShadowRenderBounds( mins, maxs, shadowType );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Re-calc our damage particles when we get a new model
//-----------------------------------------------------------------------------
CStudioHdr *C_ObjectSentrygun::OnNewModel( void )
{
	CStudioHdr *hdr = BaseClass::OnNewModel();

	UpdateDamageEffects( m_damageLevel );

	// Reset Bodygroups
	for ( int i = GetNumBodyGroups()-1; i >= 0; i-- )
	{
		SetBodygroup( i, 0 );
	}

	m_iPlacementBodygroup = FindBodygroupByName( "sentry1_range" );
	m_iPlacementBodygroup_Mini = FindBodygroupByName( "sentry1_range_mini" );

	return hdr;
}

//-----------------------------------------------------------------------------
// Purpose: Damage level has changed, update our effects
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::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 = "sentrydamage_1";
		break;
	case BUILDING_DAMAGE_LEVEL_MEDIUM:
		pszEffect = "sentrydamage_2";
		break;
	case BUILDING_DAMAGE_LEVEL_HEAVY:
		pszEffect = "sentrydamage_3";
		break;
	case BUILDING_DAMAGE_LEVEL_CRITICAL:
		pszEffect = "sentrydamage_4";
		break;

	default:
		break;
	}

	if ( Q_strlen(pszEffect) > 0 )
	{
		switch( m_iUpgradeLevel )
		{
		case 1:
		case 2:
			m_hDamageEffects = ParticleProp()->Create( pszEffect, PATTACH_POINT_FOLLOW, "build_point_0" );
			break;

		case 3:
			m_hDamageEffects = ParticleProp()->Create( pszEffect, PATTACH_POINT_FOLLOW, "sentrydamage" );
			break;
		}		
	}
}

//-----------------------------------------------------------------------------
// Purpose: placement state has changed, update the model
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::OnPlacementStateChanged( bool bValidPlacement )
{
	if ( bValidPlacement && ( m_iPlacementBodygroup >= 0 ) && ( m_iPlacementBodygroup_Mini >= 0 ) )
	{
		if ( IsMiniBuilding() )
		{
			SetBodygroup( m_iPlacementBodygroup, 0 );
			SetBodygroup( m_iPlacementBodygroup_Mini, 1 );
		}
		else
		{
			SetBodygroup( m_iPlacementBodygroup, 1 );
			SetBodygroup( m_iPlacementBodygroup_Mini, 0 );
		}
	}
	else
	{
		SetBodygroup( m_iPlacementBodygroup, 0 );
		SetBodygroup( m_iPlacementBodygroup_Mini, 0 );
	}

	BaseClass::OnPlacementStateChanged( bValidPlacement );
}

void C_ObjectSentrygun::DebugDamageParticles( void )
{
	Msg( "Health %d\n", GetHealth() );

	BuildingDamageLevel_t damageLevel = CalculateDamageLevel();
	Msg( "Damage Level %d\n", (int)damageLevel );

	if ( m_hDamageEffects )
	{
		Msg( "m_hDamageEffects is valid\n" );
	}
	else
	{
		Msg( "m_hDamageEffects is NULL\n" );
	}

	// print all particles owned by particleprop
	ParticleProp()->DebugPrintEffects();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
{
	BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );

	if ( !IsMiniBuilding() )
		return;

	if ( IsBuilding() || IsPlacing() )
		return;

	
	//Vector position;
	//for ( int i=0; i<8; ++i )
	//{
	//	matrix3x4_t &transform = GetBoneForWrite( i );
	//	MatrixGetColumn( transform, 3, position );
	//	MatrixSetColumn( Vector(0,0,-4) + position, 3, transform );
	//}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char* C_ObjectSentrygun::GetStatusName() const
{
	if ( IsDisposableBuilding() )
	{
		return "#TF_Object_Sentry_Disp";
	}
	
	return "#TF_Object_Sentry";
}