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.
465 lines
13 KiB
465 lines
13 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Client's CObjectTeleporter |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "c_baseobject.h" |
|
#include "c_tf_player.h" |
|
#include "vgui/ILocalize.h" |
|
#include "c_obj_teleporter.h" |
|
#include "soundenvelope.h" |
|
#include "vgui/ILocalize.h" |
|
#include "tf_gamerules.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
using namespace vgui; |
|
|
|
#define TELEPORTER_MINS Vector( -24, -24, 0) |
|
#define TELEPORTER_MAXS Vector( 24, 24, 12) |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Teleporter object |
|
//----------------------------------------------------------------------------- |
|
|
|
IMPLEMENT_CLIENTCLASS_DT(C_ObjectTeleporter, DT_ObjectTeleporter, CObjectTeleporter) |
|
RecvPropInt( RECVINFO(m_iState) ), |
|
RecvPropTime( RECVINFO(m_flRechargeTime) ), |
|
RecvPropTime( RECVINFO(m_flCurrentRechargeDuration) ), |
|
RecvPropInt( RECVINFO(m_iTimesUsed) ), |
|
RecvPropFloat( RECVINFO(m_flYawToExit) ), |
|
RecvPropBool( RECVINFO(m_bMatchBuilding) ), |
|
END_RECV_TABLE() |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
C_ObjectTeleporter::C_ObjectTeleporter() |
|
{ |
|
m_hChargedEffect = NULL; |
|
m_hDirectionEffect = NULL; |
|
m_hChargedLeftArmEffect = NULL; |
|
m_hChargedRightArmEffect = NULL; |
|
|
|
m_iDirectionArrowPoseParam = 0; |
|
|
|
m_pSpinSound = NULL; |
|
|
|
m_bMatchBuilding = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::UpdateOnRemove( void ) |
|
{ |
|
StopActiveEffects(); |
|
StopChargedEffects(); |
|
|
|
if ( m_pSpinSound ) |
|
{ |
|
CSoundEnvelopeController::GetController().SoundDestroy( m_pSpinSound ); |
|
} |
|
|
|
BaseClass::UpdateOnRemove(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::OnPreDataChanged( DataUpdateType_t updateType ) |
|
{ |
|
BaseClass::OnPreDataChanged( updateType ); |
|
|
|
m_iOldState = m_iState; |
|
m_bOldMatchBuilding = m_bMatchBuilding; |
|
} |
|
|
|
void C_ObjectTeleporter::StartBuildingEffects() |
|
{ |
|
StopBuildingEffects(); |
|
char szEffect[128]; |
|
|
|
// arm glow effects |
|
Q_snprintf( szEffect, sizeof(szEffect), "teleporter_arms_circle_%s_blink", ( GetTeamNumber() == TF_TEAM_RED ) ? "red" : "blue" ); |
|
|
|
Assert( m_hBuildingLeftArmEffect.m_pObject == NULL ); |
|
m_hBuildingLeftArmEffect = ParticleProp()->Create( szEffect, PATTACH_POINT_FOLLOW, 1 ); |
|
|
|
Assert( m_hBuildingRightArmEffect.m_pObject == NULL ); |
|
m_hBuildingRightArmEffect = ParticleProp()->Create( szEffect, PATTACH_POINT_FOLLOW, 3 ); |
|
} |
|
|
|
void C_ObjectTeleporter::StartChargedEffects() |
|
{ |
|
StopChargedEffects(); |
|
char szEffect[128]; |
|
|
|
Q_snprintf( szEffect, sizeof(szEffect), "teleporter_%s_charged_level%d", |
|
( GetTeamNumber() == TF_TEAM_RED ) ? "red" : "blue", GetUpgradeLevel() ); |
|
|
|
Assert( m_hChargedEffect.m_pObject == NULL ); |
|
m_hChargedEffect = ParticleProp()->Create( szEffect, PATTACH_ABSORIGIN ); |
|
} |
|
|
|
void C_ObjectTeleporter::StartActiveEffects() |
|
{ |
|
StopActiveEffects(); |
|
char szEffect[128]; |
|
|
|
Q_snprintf( szEffect, sizeof(szEffect), "teleporter_%s_%s_level%d", |
|
( GetTeamNumber() == TF_TEAM_RED ) ? "red" : "blue", |
|
GetObjectMode() == MODE_TELEPORTER_ENTRANCE ? "entrance" : "exit", |
|
GetUpgradeLevel() ); |
|
|
|
Assert( m_hDirectionEffect.m_pObject == NULL ); |
|
m_hDirectionEffect = ParticleProp()->Create( szEffect, PATTACH_ABSORIGIN ); |
|
|
|
// arm glow effects |
|
Q_snprintf( szEffect, sizeof(szEffect), "teleporter_arms_circle_%s", |
|
( GetTeamNumber() == TF_TEAM_RED ) ? "red" : "blue" ); |
|
|
|
Assert( m_hChargedLeftArmEffect.m_pObject == NULL ); |
|
m_hChargedLeftArmEffect = ParticleProp()->Create( szEffect, PATTACH_POINT_FOLLOW, 1 ); |
|
|
|
Assert( m_hChargedRightArmEffect.m_pObject == NULL ); |
|
m_hChargedRightArmEffect = ParticleProp()->Create( szEffect, PATTACH_POINT_FOLLOW, 3 ); |
|
|
|
// always reinitializes sound since this only gets called when the sound needs to start or change |
|
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); |
|
if ( m_pSpinSound ) |
|
{ |
|
controller.SoundDestroy( m_pSpinSound ); |
|
m_pSpinSound = NULL; |
|
} |
|
char szSound[128]; |
|
Q_snprintf( szSound, sizeof(szSound), "Building_Teleporter.SpinLevel%d", GetUpgradeLevel()); |
|
|
|
CLocalPlayerFilter filter; |
|
m_pSpinSound = controller.SoundCreate( filter, entindex(), szSound ); |
|
controller.Play( m_pSpinSound, 1.0, 100 ); |
|
} |
|
|
|
void C_ObjectTeleporter::StopBuildingEffects() |
|
{ |
|
if ( m_hBuildingLeftArmEffect ) |
|
{ |
|
ParticleProp()->StopEmission( m_hBuildingLeftArmEffect ); |
|
m_hBuildingLeftArmEffect = NULL; |
|
} |
|
|
|
if ( m_hBuildingRightArmEffect ) |
|
{ |
|
ParticleProp()->StopEmission( m_hBuildingRightArmEffect ); |
|
m_hBuildingRightArmEffect = NULL; |
|
} |
|
} |
|
|
|
void C_ObjectTeleporter::StopChargedEffects() |
|
{ |
|
if ( m_hChargedEffect ) |
|
{ |
|
ParticleProp()->StopEmission( m_hChargedEffect ); |
|
m_hChargedEffect = NULL; |
|
} |
|
} |
|
|
|
void C_ObjectTeleporter::StopActiveEffects() |
|
{ |
|
if ( m_hDirectionEffect ) |
|
{ |
|
ParticleProp()->StopEmission( m_hDirectionEffect ); |
|
m_hDirectionEffect = NULL; |
|
} |
|
|
|
if ( m_hChargedLeftArmEffect ) |
|
{ |
|
ParticleProp()->StopEmission( m_hChargedLeftArmEffect ); |
|
m_hChargedLeftArmEffect = NULL; |
|
} |
|
|
|
if ( m_hChargedRightArmEffect ) |
|
{ |
|
ParticleProp()->StopEmission( m_hChargedRightArmEffect ); |
|
m_hChargedRightArmEffect = NULL; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::SetInvisibilityLevel( float flValue ) |
|
{ |
|
if ( IsEnteringOrExitingFullyInvisible( flValue ) ) |
|
{ |
|
UpdateTeleporterEffects(); |
|
} |
|
|
|
BaseClass::SetInvisibilityLevel( flValue ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::UpdateTeleporterEffects( void ) |
|
{ |
|
#ifdef STAGING_ONLY |
|
C_TFPlayer *pTFOwner = GetOwner(); |
|
if ( ( pTFOwner && pTFOwner->m_Shared.IsEnteringOrExitingFullyInvisible() ) || GetInvisibilityLevel() == 1.f ) |
|
{ |
|
StopActiveEffects(); |
|
StopBuildingEffects(); |
|
StopChargedEffects(); |
|
return; |
|
} |
|
#endif // STAGING_ONLY |
|
|
|
if ( m_bMatchBuilding ) |
|
{ |
|
StartBuildingEffects(); |
|
} |
|
else |
|
{ |
|
StopBuildingEffects(); |
|
} |
|
|
|
// In MVM, teleporter from invaders act as spawn point. Always play active effect |
|
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) |
|
{ |
|
if ( m_iState != TELEPORTER_STATE_BUILDING && GetTeamNumber() == TF_TEAM_PVE_INVADERS ) |
|
{ |
|
StartChargedEffects(); |
|
StartActiveEffects(); |
|
return; |
|
} |
|
} |
|
|
|
if ( m_iState == TELEPORTER_STATE_READY ) |
|
{ |
|
StartChargedEffects(); |
|
} |
|
else |
|
{ |
|
StopChargedEffects(); |
|
} |
|
|
|
if ( m_iState > TELEPORTER_STATE_IDLE && m_iOldState <= TELEPORTER_STATE_IDLE ) |
|
{ |
|
StartActiveEffects(); |
|
} |
|
else if ( ( m_iState <= TELEPORTER_STATE_IDLE || m_iState == TELEPORTER_STATE_UPGRADING ) && m_iOldState > TELEPORTER_STATE_IDLE ) |
|
{ |
|
StopActiveEffects(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::OnDataChanged( DataUpdateType_t updateType ) |
|
{ |
|
BaseClass::OnDataChanged( updateType ); |
|
|
|
if ( m_bOldMatchBuilding != m_bMatchBuilding ) |
|
{ |
|
m_bOldMatchBuilding = m_bMatchBuilding; |
|
UpdateTeleporterEffects(); |
|
} |
|
|
|
if ( m_iOldState != m_iState ) |
|
{ |
|
UpdateTeleporterEffects(); |
|
m_iOldState = m_iState; |
|
} |
|
|
|
// update the pitch based on our playback rate |
|
if ( m_pSpinSound ) |
|
{ |
|
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); |
|
|
|
controller.SoundChangePitch( m_pSpinSound, GetPlaybackRate() * 100.0f, 0.1 ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float C_ObjectTeleporter::GetChargeTime( void ) |
|
{ |
|
float flTime = m_flRechargeTime - gpGlobals->curtime; |
|
|
|
if ( flTime < 0 ) |
|
return 0; |
|
|
|
return flTime; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int C_ObjectTeleporter::GetTimesUsed( void ) |
|
{ |
|
return m_iTimesUsed; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CStudioHdr *C_ObjectTeleporter::OnNewModel( void ) |
|
{ |
|
CStudioHdr *hdr = BaseClass::OnNewModel(); |
|
|
|
m_iDirectionArrowPoseParam = LookupPoseParameter( "direction" ); |
|
|
|
SetNextClientThink( CLIENT_THINK_ALWAYS ); |
|
|
|
return hdr; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Update the direction arrow |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::ClientThink( void ) |
|
{ |
|
if ( m_iState >= TELEPORTER_STATE_READY ) |
|
{ |
|
SetPoseParameter( m_iDirectionArrowPoseParam, m_flYawToExit); |
|
} |
|
|
|
#ifdef STAGING_ONLY |
|
C_TFPlayer *pTFOwner = GetOwner(); |
|
if ( pTFOwner && pTFOwner->m_Shared.IsEnteringOrExitingFullyInvisible() ) |
|
{ |
|
UpdateTeleporterEffects(); |
|
} |
|
#endif // STAGING_ONLY |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::GetTargetIDDataString( OUT_Z_BYTECAP(iMaxLenInBytes) wchar_t *sDataString, int iMaxLenInBytes ) |
|
{ |
|
Assert( iMaxLenInBytes >= sizeof(sDataString[0]) ); |
|
wchar_t wzBaseString[MAX_ID_STRING]; |
|
BaseClass::GetTargetIDDataString( wzBaseString, sizeof( wzBaseString ) ); |
|
|
|
sDataString[0] = '\0'; |
|
if ( m_iState == TELEPORTER_STATE_RECHARGING && gpGlobals->curtime < m_flRechargeTime ) |
|
{ |
|
float flPercent = clamp( ( m_flRechargeTime - gpGlobals->curtime ) / m_flCurrentRechargeDuration, 0.0f, 1.0f ); |
|
|
|
wchar_t wszRecharging[ 32 ]; |
|
_snwprintf( wszRecharging, ARRAYSIZE(wszRecharging) - 1, L"%.0f", 100 - (flPercent * 100) ); |
|
wszRecharging[ ARRAYSIZE(wszRecharging)-1 ] = '\0'; |
|
|
|
const char *printFormatString = "#TF_playerid_object_recharging"; |
|
|
|
g_pVGuiLocalize->ConstructString( sDataString, iMaxLenInBytes, g_pVGuiLocalize->Find(printFormatString), |
|
1, |
|
wszRecharging ); |
|
} |
|
else if ( m_iState == TELEPORTER_STATE_IDLE ) |
|
{ |
|
g_pVGuiLocalize->ConstructString( sDataString, iMaxLenInBytes, g_pVGuiLocalize->Find("#TF_playerid_teleporter_nomatch" ), 0 ); |
|
} |
|
|
|
// Concatenate the base level string |
|
V_wcsncat( sDataString, L" ", iMaxLenInBytes / sizeof( wchar_t ) ); |
|
V_wcsncat( sDataString, wzBaseString, iMaxLenInBytes / sizeof( wchar_t ) ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Damage level has changed, update our effects |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::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 = "tpdamage_1"; |
|
break; |
|
case BUILDING_DAMAGE_LEVEL_MEDIUM: |
|
pszEffect = "tpdamage_2"; |
|
break; |
|
case BUILDING_DAMAGE_LEVEL_HEAVY: |
|
pszEffect = "tpdamage_3"; |
|
break; |
|
case BUILDING_DAMAGE_LEVEL_CRITICAL: |
|
pszEffect = "tpdamage_4"; |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
|
|
if ( Q_strlen(pszEffect) > 0 ) |
|
{ |
|
m_hDamageEffects = ParticleProp()->Create( pszEffect, PATTACH_ABSORIGIN ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool C_ObjectTeleporter::IsPlacementPosValid( void ) |
|
{ |
|
bool bResult = BaseClass::IsPlacementPosValid(); |
|
|
|
if ( !bResult ) |
|
{ |
|
return false; |
|
} |
|
|
|
// m_vecBuildOrigin is the proposed build origin |
|
|
|
// start above the teleporter position |
|
Vector vecTestPos = m_vecBuildOrigin; |
|
vecTestPos.z += TELEPORTER_MAXS.z; |
|
|
|
// make sure we can fit a player on top in this pos |
|
trace_t tr; |
|
UTIL_TraceHull( vecTestPos, vecTestPos, VEC_HULL_MIN, VEC_HULL_MAX, MASK_SOLID | CONTENTS_PLAYERCLIP, this, COLLISION_GROUP_PLAYER_MOVEMENT, &tr ); |
|
|
|
return ( tr.fraction >= 1.0 ); |
|
} |
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::UpgradeLevelChanged( void ) |
|
{ |
|
StopActiveEffects(); |
|
StopChargedEffects(); |
|
|
|
if ( m_iState >= TELEPORTER_STATE_READY && m_iState != TELEPORTER_STATE_UPGRADING ) |
|
{ |
|
StartActiveEffects(); |
|
if ( m_iState != TELEPORTER_STATE_RECHARGING ) |
|
{ |
|
StartChargedEffects(); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_ObjectTeleporter::OnGoInactive( void ) |
|
{ |
|
StopActiveEffects(); |
|
StopBuildingEffects(); |
|
StopChargedEffects(); |
|
|
|
BaseClass::OnGoInactive(); |
|
}
|
|
|