diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index 921236ff9e4..d1f0a8b93c7 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1696,7 +1696,10 @@ bool CSpyInvisProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues ) return ( bInvis && bTint ); } -ConVar tf_teammate_max_invis( "tf_teammate_max_invis", "0.95", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY ); +ConVar tf_teammate_max_invis( "tf_teammate_max_invis", "0.75", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY ); + +Vector cloakTintRed = Vector( 1.0f, 0.5f, 0.4f ); +Vector cloakTintBlue = Vector( 0.4f, 0.5f, 1.0f ); //----------------------------------------------------------------------------- // Purpose: @@ -1728,22 +1731,21 @@ void CSpyInvisProxy::OnBind( C_BaseEntity *pBaseEntity ) } else { - float r = 1.0f, g = 1.0f, b = 1.0f; + Vector vecColor{ 1.0f, 1.0f, 1.0f }; fInvis = pPlayer->GetEffectiveInvisibilityLevel(); switch( pPlayer->GetTeamNumber() ) { case TF_TEAM_RED: - r = 1.0; g = 0.5; b = 0.4; + vecColor = cloakTintRed; break; - case TF_TEAM_BLUE: default: - r = 0.4; g = 0.5; b = 1.0; + vecColor = cloakTintBlue; break; } - m_pCloakColorTint->SetVecValue( r, g, b ); + m_pCloakColorTint->SetVecValue( vecColor.Base(), 3 ); } m_pPercentInvisible->SetFloatValue( fInvis ); @@ -1761,6 +1763,169 @@ void CSpyInvisProxy::OnBindNotEntity( void *pRenderable ) EXPOSE_INTERFACE( CSpyInvisProxy, IMaterialProxy, "spy_invis" IMATERIAL_PROXY_INTERFACE_VERSION ); +//----------------------------------------------------------------------------- +// Purpose: Generic invis proxy that can handle invis for both weapons & viewmodels. +// Makes the vm_invis & weapon_invis proxies obsolete, do not use them. +//----------------------------------------------------------------------------- +class CInvisProxy : public CBaseInvisMaterialProxy +{ +public: + CInvisProxy( void ); + virtual bool Init( IMaterial* pMaterial, KeyValues* pKeyValues ) OVERRIDE; + virtual void OnBind( C_BaseEntity *pC_BaseEntity ) OVERRIDE; + +private: + IMaterialVar* m_pCloakColorTint; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CInvisProxy::CInvisProxy( void ) +{ + m_pCloakColorTint = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Get pointer to the color value +// Input : *pMaterial - +//----------------------------------------------------------------------------- +bool CInvisProxy::Init( IMaterial* pMaterial, KeyValues* pKeyValues ) +{ + // Need to get the material var + bool bInvis = CBaseInvisMaterialProxy::Init( pMaterial, pKeyValues ); + + bool bTint; + m_pCloakColorTint = pMaterial->FindVar( "$cloakColorTint", &bTint ); + + return ( bInvis && bTint ); +} + +ConVar tf_viewmodel_cloak_tint( "tf_viewmodel_cloak_tint", "0", FCVAR_ARCHIVE, "Allow viewmodels to be tinted while cloaked.", true, 0.0f, true, 1.0f ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CInvisProxy::OnBind( C_BaseEntity *pC_BaseEntity ) +{ + if( !m_pPercentInvisible ) + return; + + C_BaseEntity *pEnt = pC_BaseEntity; + + C_TFPlayer *pPlayer = NULL; + float flCloakTintFactor = 1.0f; + + // Check if we are parented to a player + C_BaseEntity *pMoveParent = pEnt->GetMoveParent(); + if ( pMoveParent && pMoveParent->IsPlayer() ) + { + pPlayer = ToTFPlayer( pMoveParent ); + } + + // Check if we are a viewmodel + if ( !pPlayer ) + { + CBaseEntity *pEntParent = pMoveParent ? pMoveParent : pEnt; + + CTFViewModel *pVM = dynamic_cast( pEntParent ); + if ( pVM ) + { + pPlayer = ToTFPlayer( pVM->GetOwner() ); + + // Viewmodels use a convar for cloak tint factor + flCloakTintFactor = tf_viewmodel_cloak_tint.GetFloat(); + } + } + + // Check if we are a player + if ( !pPlayer ) + { + if ( pEnt->IsPlayer() ) + { + pPlayer = dynamic_cast( pEnt ); + } + else + { + IHasOwner *pOwnerInterface = dynamic_cast( pEnt ); + if ( pOwnerInterface ) + { + pPlayer = ToTFPlayer( pOwnerInterface->GetOwnerViaInterface() ); + } + } + } + + // Check if we are a ragdoll, otherwise give up + if ( !pPlayer ) + { + C_TFRagdoll *pRagdoll = dynamic_cast( pEnt ); + if ( pRagdoll && pRagdoll->IsCloaked() ) + { + m_pPercentInvisible->SetFloatValue( pRagdoll->GetPercentInvisible() ); + } + else + { + m_pPercentInvisible->SetFloatValue( 0.0f ); + } + return; + } + + // Cloak tinting + Vector vecColor{ 1.0f, 1.0f, 1.0f }; + + if ( pPlayer ) + { + // We were validated, color as necessary + switch ( pPlayer->GetTeamNumber() ) + { + case TF_TEAM_RED: + vecColor = cloakTintRed; + break; + case TF_TEAM_BLUE: + default: + vecColor = cloakTintBlue; + break; + } + } + + // Blend the color based on cloak tint factor, if applicable + if( flCloakTintFactor != 1.0f ) + { + VectorLerp( Vector( 1.0f, 1.0f, 1.0f ), vecColor, flCloakTintFactor, vecColor ); + } + m_pCloakColorTint->SetVecValue( vecColor.Base(), 3 ); + + // Handle the local player + if ( pPlayer->IsLocalPlayer() ) + { + float flPercentInvisible = pPlayer->GetEffectiveInvisibilityLevel(); + float flWeaponInvis = flPercentInvisible; + + // Reveal ourself a little when bumping into players + if ( pPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) ) + { + flWeaponInvis = 0.3f; + } + + // Reveal ourself a little if we're using motion cloak and our well has run dry + CTFWeaponInvis *pWpn = (CTFWeaponInvis *) pPlayer->Weapon_OwnsThisID( TF_WEAPON_INVIS ); + if ( pWpn && pWpn->HasMotionCloak() && (pPlayer->m_Shared.GetSpyCloakMeter() <= 0.f ) ) + { + flWeaponInvis = 0.3f; + } + + m_pPercentInvisible->SetFloatValue( flWeaponInvis ); + } + else + { + m_pPercentInvisible->SetFloatValue( pPlayer->GetEffectiveInvisibilityLevel() ); + } +} + +// Generic invis proxy that can handle invis for both weapons & viewmodels. +// Makes the vm_invis & weapon_invis proxies obsolete, do not use them. +EXPOSE_INTERFACE( CInvisProxy, IMaterialProxy, "invis" IMATERIAL_PROXY_INTERFACE_VERSION ); + //----------------------------------------------------------------------------- // Purpose: Used for invulnerability material // Returns 1 if the player is invulnerable, and 0 if the player is losing / doesn't have invuln. @@ -6790,7 +6955,8 @@ float C_TFPlayer::GetEffectiveInvisibilityLevel( void ) } // stomp invis level with taunt invis if there's one - if ( IsTaunting() ) + // boba: unused attribute, adds needless expense to GetEffectiveInvisibilityLevel() every frame + /*if (IsTaunting()) { float flTauntInvis = 0.f; CALL_ATTRIB_HOOK_FLOAT( flTauntInvis, taunt_attr_player_invis_percent ); @@ -6798,7 +6964,7 @@ float C_TFPlayer::GetEffectiveInvisibilityLevel( void ) { flPercentInvisible = flTauntInvis; } - } + }*/ return flPercentInvisible; } diff --git a/src/game/shared/tf/tf_viewmodel.cpp b/src/game/shared/tf/tf_viewmodel.cpp index 4ef8892c078..0d45a928199 100644 --- a/src/game/shared/tf/tf_viewmodel.cpp +++ b/src/game/shared/tf/tf_viewmodel.cpp @@ -474,16 +474,16 @@ void CViewModelInvisProxy::OnBind( C_BaseEntity *pEnt ) return; } - float flPercentInvisible = pPlayer->GetPercentInvisible(); + float flPercentInvisible = pPlayer->GetEffectiveInvisibilityLevel(); float flWeaponInvis = flPercentInvisible; if ( bIsViewModel == true ) { // remap from 0.22 to 0.5 // but drop to 0.0 if we're not invis at all - flWeaponInvis = ( flPercentInvisible < 0.01 ) ? + flWeaponInvis = (flPercentInvisible < 0.01) ? 0.0 : - RemapVal( flPercentInvisible, 0.0, 1.0, TF_VM_MIN_INVIS, TF_VM_MAX_INVIS ); + RemapVal(flPercentInvisible, 0.0, 1.0, TF_VM_MIN_INVIS, TF_VM_MAX_INVIS); // Exaggerated blink effect on bump. if ( pPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) ) @@ -504,110 +504,4 @@ void CViewModelInvisProxy::OnBind( C_BaseEntity *pEnt ) EXPOSE_INTERFACE( CViewModelInvisProxy, IMaterialProxy, "vm_invis" IMATERIAL_PROXY_INTERFACE_VERSION ); - -//----------------------------------------------------------------------------- -// Purpose: Generic invis proxy that can handle invis for both weapons & viewmodels. -// Makes the vm_invis & weapon_invis proxies obsolete, do not use them. -//----------------------------------------------------------------------------- -class CInvisProxy : public CBaseInvisMaterialProxy -{ -public: - virtual void OnBind( C_BaseEntity *pC_BaseEntity ) OVERRIDE; -}; - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CInvisProxy::OnBind( C_BaseEntity *pC_BaseEntity ) -{ - if( !m_pPercentInvisible ) - return; - - C_BaseEntity *pEnt = pC_BaseEntity; - - CTFPlayer *pPlayer = NULL; - - // Check if we have a move parent and if it's a player - C_BaseEntity *pMoveParent = pEnt->GetMoveParent(); - if ( pMoveParent && pMoveParent->IsPlayer() ) - { - pPlayer = ToTFPlayer( pMoveParent ); - } - - // If it's not a player then check for viewmodel. - if ( !pPlayer ) - { - CBaseEntity *pEntParent = pMoveParent ? pMoveParent : pEnt; - - CTFViewModel *pVM = dynamic_cast( pEntParent ); - if ( pVM ) - { - pPlayer = ToTFPlayer( pVM->GetOwner() ); - } - } - - if ( !pPlayer ) - { - if ( pEnt->IsPlayer() ) - { - pPlayer = dynamic_cast( pEnt ); - } - else - { - IHasOwner *pOwnerInterface = dynamic_cast( pEnt ); - if ( pOwnerInterface ) - { - pPlayer = ToTFPlayer( pOwnerInterface->GetOwnerViaInterface() ); - } - } - } - - if ( !pPlayer ) - { - C_TFRagdoll *pRagdoll = dynamic_cast( pEnt ); - if ( !pRagdoll || !pRagdoll->IsCloaked() ) - { - m_pPercentInvisible->SetFloatValue( 0.0f ); - } - return; - } - - // If we're the local player, use the old "vm_invis" code. Otherwise, use the "weapon_invis". - if ( pPlayer->IsLocalPlayer() ) - { - float flPercentInvisible = pPlayer->GetPercentInvisible(); - float flWeaponInvis = flPercentInvisible; - - // remap from 0.22 to 0.5 - // but drop to 0.0 if we're not invis at all - flWeaponInvis = ( flPercentInvisible < 0.01 ) ? - 0.0 : - RemapVal( flPercentInvisible, 0.0, 1.0, TF_VM_MIN_INVIS, TF_VM_MAX_INVIS ); - - // Exaggerated blink effect on bump. - if ( pPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) ) - { - flWeaponInvis = 0.3f; - } - - // Also exaggerate the effect if we're using motion cloak and our well has run dry. - CTFWeaponInvis *pWpn = (CTFWeaponInvis *) pPlayer->Weapon_OwnsThisID( TF_WEAPON_INVIS ); - if ( pWpn && pWpn->HasMotionCloak() && (pPlayer->m_Shared.GetSpyCloakMeter() <= 0.f ) ) - { - flWeaponInvis = 0.3f; - } - - m_pPercentInvisible->SetFloatValue( flWeaponInvis ); - } - else - { - m_pPercentInvisible->SetFloatValue( pPlayer->GetEffectiveInvisibilityLevel() ); - } -} - -// Generic invis proxy that can handle invis for both weapons & viewmodels. -// Makes the vm_invis & weapon_invis proxies obsolete, do not use them. -EXPOSE_INTERFACE( CInvisProxy, IMaterialProxy, "invis" IMATERIAL_PROXY_INTERFACE_VERSION ); - - #endif // CLIENT_DLL