diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index 921236ff9e..804a129640 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -3695,6 +3695,7 @@ END_RECV_TABLE() //----------------------------------------------------------------------------- BEGIN_RECV_TABLE_NOBASE( C_TFPlayer, DT_TFSendHealersDataTable ) RecvPropInt( RECVINFO( m_nActiveWpnClip ) ), + RecvPropInt( RECVINFO( m_nActiveWpnReserve ) ), END_RECV_TABLE() IMPLEMENT_CLIENTCLASS_DT( C_TFPlayer, DT_TFPlayer, CTFPlayer ) @@ -9724,14 +9725,23 @@ void C_TFPlayer::GetTargetIDDataString( bool bIsDisguised, OUT_Z_BYTECAP(iMaxLen } // Show target's clip state to attached medics - if ( !sDataString[0] && m_nActiveWpnClip >= 0 ) + if ( !sDataString[0] && m_nActiveWpnClip != UINT16_MAX ) { C_TFPlayer *pTFHealTarget = ToTFPlayer( pLocalPlayer->MedicGetHealTarget() ); if ( pTFHealTarget && pTFHealTarget == this ) { wchar_t wszClip[10]; - V_snwprintf( wszClip, ARRAYSIZE(wszClip) - 1, L"%d", m_nActiveWpnClip ); - g_pVGuiLocalize->ConstructString( sDataString, iMaxLenInBytes, g_pVGuiLocalize->Find( "#TF_playerid_ammo" ), 1, wszClip ); + V_snwprintf( wszClip, ARRAYSIZE( wszClip ) - 1, L"%d", m_nActiveWpnClip ); + if ( m_nActiveWpnReserve != UINT16_MAX ) + { + wchar_t wszReserve[10]; + V_snwprintf( wszReserve, ARRAYSIZE( wszReserve ) - 1, L"%d", m_nActiveWpnReserve ); + g_pVGuiLocalize->ConstructString( sDataString, iMaxLenInBytes, g_pVGuiLocalize->Find( "#TF_playerid_ammo_reserve" ), 2, wszClip, wszReserve ); + } + else + { + g_pVGuiLocalize->ConstructString( sDataString, iMaxLenInBytes, g_pVGuiLocalize->Find("#TF_playerid_ammo" ), 1, wszClip ); + } bIsAmmoData = true; } } diff --git a/src/game/client/tf/c_tf_player.h b/src/game/client/tf/c_tf_player.h index 0fcee37308..f122b0754b 100644 --- a/src/game/client/tf/c_tf_player.h +++ b/src/game/client/tf/c_tf_player.h @@ -874,6 +874,7 @@ class C_TFPlayer : public C_BasePlayer, public IHasAttributes, public IInventory // Medic healtarget active weapon ammo/clip count uint16 m_nActiveWpnClip; + uint16 m_nActiveWpnReserve; // Blast jump whistle CSoundPatch *m_pBlastJumpLoop; diff --git a/src/game/server/tf/tf_player.cpp b/src/game/server/tf/tf_player.cpp index b83535ce55..49c1f379be 100644 --- a/src/game/server/tf/tf_player.cpp +++ b/src/game/server/tf/tf_player.cpp @@ -613,6 +613,8 @@ BEGIN_ENT_SCRIPTDESC( CTFPlayer, CBaseMultiplayerPlayer , "Team Fortress 2 Playe DEFINE_SCRIPTFUNC_NAMED( ScriptIsImmuneToPushback, "IsImmuneToPushback", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetDisguiseAmmoCount, "GetDisguiseAmmoCount", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetDisguiseAmmoCount, "SetDisguiseAmmoCount", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetDisguiseAmmoReserveCount, "GetDisguiseAmmoReserveCount", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetDisguiseAmmoReserveCount, "SetDisguiseAmmoReserveCount", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetDisguiseTeam, "GetDisguiseTeam", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptIsFullyInvisible, "IsFullyInvisible", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetSpyCloakMeter, "GetSpyCloakMeter", "" ) @@ -756,7 +758,8 @@ END_SEND_TABLE() // Purpose: Sent to attached medics //----------------------------------------------------------------------------- BEGIN_SEND_TABLE_NOBASE( CTFPlayer, DT_TFSendHealersDataTable ) - SendPropInt( SENDINFO( m_nActiveWpnClip ), -1, SPROP_VARINT | SPROP_UNSIGNED ), + SendPropInt( SENDINFO( m_nActiveWpnClip ), 0, SPROP_VARINT | SPROP_UNSIGNED ), + SendPropInt( SENDINFO( m_nActiveWpnReserve ), 0, SPROP_VARINT | SPROP_UNSIGNED ), END_SEND_TABLE() //============ @@ -1058,7 +1061,9 @@ CTFPlayer::CTFPlayer() ResetDamagePerSecond(); m_nActiveWpnClip.Set( 0 ); + m_nActiveWpnReserve.Set( 0 ); m_nActiveWpnClipPrev = 0; + m_nActiveWpnReservePrev = 0; m_flNextClipSendTime = 0; m_nCanPurchaseUpgradesCount = 0; @@ -1626,26 +1631,32 @@ void CTFPlayer::TFPlayerThink() CTFWeaponBase *pTFWeapon = GetActiveTFWeapon(); if ( pTFWeapon ) { - int nClip = 0; + int nClip = UINT16_MAX, nReserve = UINT16_MAX; if ( m_Shared.InCond( TF_COND_DISGUISED ) ) { nClip = m_Shared.GetDisguiseAmmoCount(); + nReserve = m_Shared.GetDisguiseAmmoReserveCount(); } - else + else if ( pTFWeapon->UsesPrimaryAmmo() ) { - nClip = pTFWeapon->UsesClipsForAmmo1() ? pTFWeapon->Clip1() : GetAmmoCount( pTFWeapon->GetPrimaryAmmoType() ); + if ( pTFWeapon->UsesClipsForAmmo1() && !pTFWeapon->IsMeleeWeapon() ) + { + nClip = pTFWeapon->Clip1(); + nReserve = GetAmmoCount( pTFWeapon->GetPrimaryAmmoType() ); + } + else + { + nClip = GetAmmoCount( pTFWeapon->GetPrimaryAmmoType() ); + } } - if ( nClip >= 0 && nClip != m_nActiveWpnClipPrev ) + if ( ( nClip != m_nActiveWpnClipPrev ) || ( nReserve != m_nActiveWpnReservePrev ) ) { - if ( nClip > 500 ) - { - Warning( "Heal Target: ClipSize Data Limit Exceeded: %d (max 500)\n", nClip ); - nClip = MIN( nClip, 500 ); - } m_nActiveWpnClip.Set( nClip ); m_nActiveWpnClipPrev = m_nActiveWpnClip; + m_nActiveWpnReserve.Set( nReserve ); + m_nActiveWpnReservePrev = m_nActiveWpnReserve; m_flNextClipSendTime = gpGlobals->curtime + 0.25f; } } diff --git a/src/game/server/tf/tf_player.h b/src/game/server/tf/tf_player.h index 87620ffed5..15df03741f 100644 --- a/src/game/server/tf/tf_player.h +++ b/src/game/server/tf/tf_player.h @@ -747,43 +747,45 @@ class CTFPlayer : public CBaseMultiplayerPlayer, public IHasAttributes, public I void ScriptSetCondDuration( int nCond, float flNewDuration ); HSCRIPT ScriptGetDisguiseTarget(); - bool ScriptIsCarryingRune() { return m_Shared.IsCarryingRune(); } - bool ScriptIsCritBoosted( void ) const { return m_Shared.IsCritBoosted(); } - bool ScriptIsInvulnerable( void ) const { return m_Shared.IsInvulnerable(); } - bool ScriptIsStealthed( void ) const { return m_Shared.IsStealthed(); } - bool ScriptCanBeDebuffed( void ) const { return m_Shared.CanBeDebuffed(); } - bool ScriptIsImmuneToPushback( void ) const { return m_Shared.IsImmuneToPushback(); } - int ScriptGetDisguiseAmmoCount() { return m_Shared.GetDisguiseAmmoCount(); } - void ScriptSetDisguiseAmmoCount( int nValue ) { return m_Shared.SetDisguiseAmmoCount(nValue); } - int ScriptGetDisguiseTeam() { return m_Shared.GetDisguiseTeam(); } - bool ScriptIsFullyInvisible() { return m_Shared.IsFullyInvisible(); } - float ScriptGetSpyCloakMeter() { return m_Shared.GetSpyCloakMeter(); } - void ScriptSetSpyCloakMeter( float flValue ) { return m_Shared.SetSpyCloakMeter( flValue ); } - bool ScriptIsRageDraining() { return m_Shared.IsRageDraining(); } - float ScriptGetRageMeter() { return m_Shared.GetRageMeter(); } - void ScriptSetRageMeter( float flValue ) { return m_Shared.SetRageMeter( flValue ); } - float ScriptGetScoutHypeMeter() { return m_Shared.GetScoutHypeMeter(); } - void ScriptSetScoutHypeMeter( float flValue ) { return m_Shared.SetScoutHypeMeter( flValue ); } - bool ScriptIsHypeBuffed() { return m_Shared.IsHypeBuffed(); } - bool ScriptIsJumping() { return m_Shared.IsJumping(); } - bool ScriptIsAirDashing() { return m_Shared.IsAirDashing(); } - bool ScriptIsControlStunned() { return m_Shared.IsControlStunned(); } - bool ScriptIsSnared() { return m_Shared.IsSnared(); } - int ScriptGetCaptures() const { return m_Shared.GetCaptures( 0 ); } - int ScriptGetDefenses() const { return m_Shared.GetDefenses( 0 ); } - int ScriptGetDominations() const { return m_Shared.GetDominations( 0 ); } - int ScriptGetRevenge() const { return m_Shared.GetRevenge( 0 ); } - int ScriptGetBuildingsDestroyed() const { return m_Shared.GetBuildingsDestroyed( 0 ); } - int ScriptGetHeadshots() const { return m_Shared.GetHeadshots( 0 ); } - int ScriptGetBackstabs() const { return m_Shared.GetBackstabs( 0 ); } - int ScriptGetHealPoints() const { return m_Shared.GetHealPoints( 0 ); } - int ScriptGetInvulns() const { return m_Shared.GetInvulns( 0 ); } - int ScriptGetTeleports() const { return m_Shared.GetTeleports( 0 ); } - int ScriptGetResupplyPoints() const { return m_Shared.GetResupplyPoints( 0 ); } - int ScriptGetKillAssists() const { return m_Shared.GetKillAssists( 0 ); } - int ScriptGetBonusPoints() const { return m_Shared.GetBonusPoints( 0 ); } - void ScriptResetScores() { m_Shared.ResetScores(); } - bool ScriptIsParachuteEquipped() { return m_Shared.IsParachuteEquipped(); } + bool ScriptIsCarryingRune() { return m_Shared.IsCarryingRune(); } + bool ScriptIsCritBoosted( void ) const { return m_Shared.IsCritBoosted(); } + bool ScriptIsInvulnerable( void ) const { return m_Shared.IsInvulnerable(); } + bool ScriptIsStealthed( void ) const { return m_Shared.IsStealthed(); } + bool ScriptCanBeDebuffed( void ) const { return m_Shared.CanBeDebuffed(); } + bool ScriptIsImmuneToPushback( void ) const { return m_Shared.IsImmuneToPushback(); } + int ScriptGetDisguiseAmmoCount() { return m_Shared.GetDisguiseAmmoCount(); } + void ScriptSetDisguiseAmmoCount( int nValue ) { return m_Shared.SetDisguiseAmmoCount(nValue); } + int ScriptGetDisguiseAmmoReserveCount() { return m_Shared.GetDisguiseAmmoReserveCount(); } + void ScriptSetDisguiseAmmoReserveCount( int nValue ) { return m_Shared.SetDisguiseAmmoReserveCount(nValue); } + int ScriptGetDisguiseTeam() { return m_Shared.GetDisguiseTeam(); } + bool ScriptIsFullyInvisible() { return m_Shared.IsFullyInvisible(); } + float ScriptGetSpyCloakMeter() { return m_Shared.GetSpyCloakMeter(); } + void ScriptSetSpyCloakMeter( float flValue ) { return m_Shared.SetSpyCloakMeter( flValue ); } + bool ScriptIsRageDraining() { return m_Shared.IsRageDraining(); } + float ScriptGetRageMeter() { return m_Shared.GetRageMeter(); } + void ScriptSetRageMeter( float flValue ) { return m_Shared.SetRageMeter( flValue ); } + float ScriptGetScoutHypeMeter() { return m_Shared.GetScoutHypeMeter(); } + void ScriptSetScoutHypeMeter( float flValue ) { return m_Shared.SetScoutHypeMeter( flValue ); } + bool ScriptIsHypeBuffed() { return m_Shared.IsHypeBuffed(); } + bool ScriptIsJumping() { return m_Shared.IsJumping(); } + bool ScriptIsAirDashing() { return m_Shared.IsAirDashing(); } + bool ScriptIsControlStunned() { return m_Shared.IsControlStunned(); } + bool ScriptIsSnared() { return m_Shared.IsSnared(); } + int ScriptGetCaptures() const { return m_Shared.GetCaptures( 0 ); } + int ScriptGetDefenses() const { return m_Shared.GetDefenses( 0 ); } + int ScriptGetDominations() const { return m_Shared.GetDominations( 0 ); } + int ScriptGetRevenge() const { return m_Shared.GetRevenge( 0 ); } + int ScriptGetBuildingsDestroyed() const { return m_Shared.GetBuildingsDestroyed( 0 ); } + int ScriptGetHeadshots() const { return m_Shared.GetHeadshots( 0 ); } + int ScriptGetBackstabs() const { return m_Shared.GetBackstabs( 0 ); } + int ScriptGetHealPoints() const { return m_Shared.GetHealPoints( 0 ); } + int ScriptGetInvulns() const { return m_Shared.GetInvulns( 0 ); } + int ScriptGetTeleports() const { return m_Shared.GetTeleports( 0 ); } + int ScriptGetResupplyPoints() const { return m_Shared.GetResupplyPoints( 0 ); } + int ScriptGetKillAssists() const { return m_Shared.GetKillAssists( 0 ); } + int ScriptGetBonusPoints() const { return m_Shared.GetBonusPoints( 0 ); } + void ScriptResetScores() { m_Shared.ResetScores(); } + bool ScriptIsParachuteEquipped() { return m_Shared.IsParachuteEquipped(); } int ScriptGetPlayerClass() { @@ -1391,7 +1393,9 @@ class CTFPlayer : public CBaseMultiplayerPlayer, public IHasAttributes, public I int m_peakDamagePerSecond; CNetworkVar( uint16, m_nActiveWpnClip ); + CNetworkVar( uint16, m_nActiveWpnReserve ); uint16 m_nActiveWpnClipPrev; + uint16 m_nActiveWpnReservePrev; float m_flNextClipSendTime; float m_flWaterExitTime; diff --git a/src/game/shared/tf/tf_player_shared.cpp b/src/game/shared/tf/tf_player_shared.cpp index a2c26261d7..e904357588 100644 --- a/src/game/shared/tf/tf_player_shared.cpp +++ b/src/game/shared/tf/tf_player_shared.cpp @@ -7231,6 +7231,7 @@ void CTFPlayerShared::OnRemoveDisguised( void ) m_iDisguiseHealth = 0; SetDisguiseBody( 0 ); m_iDisguiseAmmo = 0; + m_iDisguiseAmmoReserve = 0; // Update the player model and skin. m_pOuter->UpdateModel(); @@ -8477,8 +8478,10 @@ void CTFPlayerShared::DetermineDisguiseWeapon( bool bForcePrimary ) // Ammo/clip state is displayed to attached medics - m_iDisguiseAmmo = 0; - if ( !m_hDisguiseWeapon->IsMeleeWeapon() ) + m_iDisguiseAmmo = UINT16_MAX; + m_iDisguiseAmmoReserve = UINT16_MAX; + + if ( m_hDisguiseWeapon->UsesPrimaryAmmo() ) { // Use the player we're disguised as if possible if ( pDisguiseTarget ) @@ -8486,20 +8489,38 @@ void CTFPlayerShared::DetermineDisguiseWeapon( bool bForcePrimary ) CTFWeaponBase *pWeapon = pDisguiseTarget->GetActiveTFWeapon(); if ( pWeapon && pWeapon->GetWeaponID() == m_hDisguiseWeapon->GetWeaponID() ) { - m_iDisguiseAmmo = pWeapon->UsesClipsForAmmo1() ? - pWeapon->Clip1() : - pDisguiseTarget->GetAmmoCount( pWeapon->GetPrimaryAmmoType() ); + if ( pWeapon->UsesClipsForAmmo1() && !pWeapon->IsMeleeWeapon() ) + { + m_iDisguiseAmmo = pWeapon->Clip1(); + m_iDisguiseAmmoReserve = pDisguiseTarget->GetAmmoCount( pWeapon->GetPrimaryAmmoType() ); + } + else + { + m_iDisguiseAmmo = pDisguiseTarget->GetAmmoCount( pWeapon->GetPrimaryAmmoType() ); + } } } // Otherwise display a faked ammo count - if ( !m_iDisguiseAmmo ) + if ( m_iDisguiseAmmo == UINT16_MAX ) { - int nMaxCount = m_hDisguiseWeapon->UsesClipsForAmmo1() ? - m_hDisguiseWeapon->GetMaxClip1() : - m_pOuter->GetMaxAmmo( m_hDisguiseWeapon->GetPrimaryAmmoType(), m_nDisguiseClass ); - - m_iDisguiseAmmo = (int)random->RandomInt( 1, nMaxCount ); + int nMaxAmmo = 0, nMaxReserve = 0; + if ( m_hDisguiseWeapon->UsesClipsForAmmo1() && !m_hDisguiseWeapon->IsMeleeWeapon() ) + { + nMaxAmmo = m_hDisguiseWeapon->GetMaxClip1(); + nMaxReserve = m_pOuter->GetMaxAmmo( m_hDisguiseWeapon->GetPrimaryAmmoType(), m_nDisguiseClass ); + } + else + { + nMaxAmmo = m_pOuter->GetMaxAmmo( m_hDisguiseWeapon->GetPrimaryAmmoType(), m_nDisguiseClass ); + } + + m_iDisguiseAmmo = (int)random->RandomInt( 1, nMaxAmmo ); + + if ( nMaxReserve ) + { + m_iDisguiseAmmoReserve = (int)random->RandomInt( 1, nMaxReserve ); + } } } } diff --git a/src/game/shared/tf/tf_player_shared.h b/src/game/shared/tf/tf_player_shared.h index fdaef92149..e2f9d7a4ff 100644 --- a/src/game/shared/tf/tf_player_shared.h +++ b/src/game/shared/tf/tf_player_shared.h @@ -389,6 +389,8 @@ class CTFPlayerShared : public CGameEventListener void ProcessDisguiseImpulse( CTFPlayer *pPlayer ); int GetDisguiseAmmoCount( void ) { return m_iDisguiseAmmo; } void SetDisguiseAmmoCount( int nValue ) { m_iDisguiseAmmo = nValue; } + int GetDisguiseAmmoReserveCount( void ) { return m_iDisguiseAmmoReserve; } + void SetDisguiseAmmoReserveCount( int nValue ) { m_iDisguiseAmmoReserve = nValue; } bool CanRecieveMedigunChargeEffect( medigun_charge_types eType ) const; #ifdef CLIENT_DLL @@ -960,6 +962,7 @@ class CTFPlayerShared : public CGameEventListener CNetworkVar( int, m_nTeamTeleporterUsed ); // for disguised spies using enemy teleporters CHandle m_hDesiredDisguiseTarget; int m_iDisguiseAmmo; + int m_iDisguiseAmmoReserve; bool m_bEnableSeparation; // Keeps separation forces on when player stops moving, but still penetrating Vector m_vSeparationVelocity; // Velocity used to keep player separate from teammates