Guest User

TF2C paintball rifle

a guest
Jan 23rd, 2025
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 36.51 KB | None | 0 0
  1. //====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6.  
  7. #include "cbase.h"
  8. #include "tf_weapon_paintballrifle.h"
  9. #include "tf_weapon_sniperrifle.h"
  10. #include "in_buttons.h"
  11. #include "tf_gamerules.h"
  12.  
  13. #ifdef CLIENT_DLL
  14. #include "functionproxy.h"
  15. #include "c_tf_player.h"
  16. #else
  17. #include "tf_player.h"
  18. #endif
  19.  
  20. extern ConVar tf2c_medigun_setup_uber;
  21. extern ConVar tf2c_medigun_multi_uber_drain;
  22. extern ConVar tf2c_medigun_critboostable;
  23. extern ConVar tf2c_medigun_4team_uber_rate;
  24. extern ConVar weapon_medigun_damage_modifier;
  25. extern ConVar weapon_medigun_construction_rate;
  26. extern ConVar weapon_medigun_charge_rate;
  27. extern ConVar weapon_medigun_chargerelease_rate;
  28.  
  29. //=============================================================================
  30. //
  31. // Weapon Paintball Rifle tables.
  32. //
  33.  
  34. #ifdef GAME_DLL
  35. //-----------------------------------------------------------------------------
  36. // Purpose: SendProxy that converts the Healing list UtlVector to entindices
  37. //-----------------------------------------------------------------------------
  38. void SendProxy_MarkedList( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  39. {
  40.     CTFPaintballRifle *pPainter = (CTFPaintballRifle *)pStruct;
  41.  
  42.     // If this assertion fails, then SendProxyArrayLength_HealingArray must have failed.
  43.     Assert( iElement < pPainter->m_vAutoHealTargets.Count() );
  44.  
  45.     EHANDLE hOther = pPainter->m_vAutoHealTargets[iElement].Get();
  46.     SendProxy_EHandleToInt( pProp, pStruct, &hOther, pOut, iElement, objectID );
  47. }
  48.  
  49. int SendProxyArrayLength_MarkedArray( const void *pStruct, int objectID )
  50. {
  51.     return ((CTFPaintballRifle *)pStruct)->m_vAutoHealTargets.Count();
  52. }
  53. #else
  54. //-----------------------------------------------------------------------------
  55. // Purpose: RecvProxy that converts the Team's player UtlVector to entindexes.
  56. //-----------------------------------------------------------------------------
  57. void RecvProxy_MarkedList( const CRecvProxyData *pData, void *pStruct, void *pOut )
  58. {
  59.     CTFPaintballRifle *pPainter = (CTFPaintballRifle *)pStruct;
  60.  
  61.     CBaseHandle *pHandle = (CBaseHandle *)(&pPainter->m_vAutoHealTargets[pData->m_iElement]);
  62.     RecvProxy_IntToEHandle( pData, pStruct, pHandle );
  63.  
  64.     // Update the heal beams.
  65.     pPainter->UpdateBackpackTargets();
  66. }
  67.  
  68. void RecvProxyArrayLength_MarkedArray( void *pStruct, int objectID, int currentArrayLength )
  69. {
  70.     CTFPaintballRifle *pPainter = (CTFPaintballRifle *)pStruct;
  71.     if ( pPainter->m_vAutoHealTargets.Size() != currentArrayLength )
  72.     {
  73.         pPainter->m_vAutoHealTargets.SetSize( currentArrayLength );
  74.     }
  75.  
  76.     // Update the beams.
  77.     pPainter->UpdateBackpackTargets();
  78. }
  79.  
  80. void RecvProxy_MainPatient( const CRecvProxyData *pData, void *pStruct, void *pOut )
  81. {
  82.     CTFPaintballRifle *pMedigun = (CTFPaintballRifle *)pStruct;
  83.     if ( pMedigun )
  84.     {
  85.         pMedigun-> // Trigger main target update
  86.             m_bMainTargetParity = !pMedigun->m_bMainTargetParity;
  87.     }
  88.  
  89.     RecvProxy_IntToEHandle( pData, pStruct, pOut );
  90. }
  91.  
  92. #endif
  93.  
  94. //CREATE_SIMPLE_WEAPON_TABLE( TFPaintballRifle, tf_weapon_paintballrifle )
  95.  
  96. LINK_ENTITY_TO_CLASS( tf_weapon_paintballrifle, CTFPaintballRifle );
  97. PRECACHE_WEAPON_REGISTER( tf_weapon_paintballrifle );
  98. IMPLEMENT_NETWORKCLASS_ALIASED( TFPaintballRifle, DT_TFPaintballRifle )
  99. BEGIN_NETWORK_TABLE( CTFPaintballRifle, DT_TFPaintballRifle )
  100. #if !defined( CLIENT_DLL )
  101. SendPropBool( SENDINFO( m_bBackpackTargetsParity ) ),
  102. SendPropArray2(
  103. SendProxyArrayLength_MarkedArray,
  104. SendPropInt( "paintballbp_array_element", 0, SIZEOF_IGNORE, NUM_NETWORKED_EHANDLE_BITS, SPROP_UNSIGNED, SendProxy_MarkedList ),
  105. MAX_PLAYERS,
  106. 0,
  107. "paintballbp_array"
  108. ),
  109. SendPropEHandle( SENDINFO( m_hMainPatient ) ),
  110. SendPropInt( SENDINFO( m_iMainPatientHealthLast ) ),
  111. SendPropBool( SENDINFO( m_bMainTargetParity ) ),
  112. SendPropTime( SENDINFO( m_flUnzoomTime ) ),
  113. SendPropTime( SENDINFO( m_flRezoomTime ) ),
  114. SendPropBool( SENDINFO( m_bRezoomAfterShot ) ),
  115. SendPropFloat( SENDINFO( m_flChargeLevel ), 0, SPROP_NOSCALE | SPROP_CHANGES_OFTEN ),
  116. SendPropBool( SENDINFO( m_bChargeRelease ) ),
  117. #else
  118. RecvPropBool( RECVINFO( m_bBackpackTargetsParity ) ),
  119. RecvPropArray2(
  120. RecvProxyArrayLength_MarkedArray,
  121. RecvPropInt( "paintballbp_array_element", 0, SIZEOF_IGNORE, 0, RecvProxy_MarkedList ),
  122. MAX_PLAYERS,
  123. 0,
  124. "paintballbp_array"
  125. ),
  126. RecvPropEHandle( RECVINFO( m_hMainPatient ), RecvProxy_MainPatient ),
  127. RecvPropInt( RECVINFO( m_iMainPatientHealthLast ) ),
  128. RecvPropBool( RECVINFO( m_bMainTargetParity ) ),
  129. RecvPropTime( RECVINFO( m_flUnzoomTime ) ),
  130. RecvPropTime( RECVINFO( m_flRezoomTime ) ),
  131. RecvPropBool( RECVINFO( m_bRezoomAfterShot ) ),
  132. RecvPropFloat( RECVINFO( m_flChargeLevel ) ),
  133. RecvPropBool( RECVINFO( m_bChargeRelease ) ),
  134. #endif
  135. END_NETWORK_TABLE()
  136.  
  137. BEGIN_PREDICTION_DATA( CTFPaintballRifle )
  138. #ifdef CLIENT_DLL
  139. DEFINE_PRED_FIELD( m_bUpdateBackpackTargets, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  140. #endif
  141. END_PREDICTION_DATA()
  142.  
  143. //=============================================================================
  144. //
  145. // Weapon Paintball Rifle functions.
  146. //
  147.  
  148.  
  149. CTFPaintballRifle::CTFPaintballRifle()
  150. {
  151.     m_bMainTargetParity = false;
  152. #ifdef CLIENT_DLL
  153.     m_bMainTargetParityOld = false;
  154.     m_pHealSoundManager = new CTFHealSoundManager( GetTFPlayerOwner(), this );
  155.  
  156.     // Not sure which of these two methods is better.
  157.     //gameeventmanager->AddListener( this, "patient_healed_notify", false );
  158.     ListenForGameEvent( "patient_healed_notify" );
  159. #else
  160.     m_bMainPatientFlaggedForRemoval = false;
  161. #endif
  162. }
  163.  
  164. CTFPaintballRifle::~CTFPaintballRifle()
  165. {
  166. #ifdef CLIENT_DLL
  167.     if ( m_pHealSoundManager )
  168.     {
  169.         m_pHealSoundManager->RemoveSound();
  170.         delete m_pHealSoundManager;
  171.         m_pHealSoundManager = NULL;
  172.     }
  173. #endif
  174. }
  175.  
  176.  
  177. void CTFPaintballRifle::WeaponReset()
  178. {
  179.     BaseClass::WeaponReset();
  180.    
  181.     m_flChargeLevel = 0.0f;
  182.     m_bChargeRelease = false;
  183.  
  184.     m_bMainTargetParity = false;
  185. #ifdef CLIENT_DLL
  186.     m_bMainTargetParityOld = false;
  187.     if ( m_pHealSoundManager )
  188.     {
  189.         m_pHealSoundManager->RemoveSound();
  190.         delete m_pHealSoundManager;
  191.         m_pHealSoundManager = NULL;
  192.     }
  193.     m_pHealSoundManager = new CTFHealSoundManager( GetTFPlayerOwner(), this );
  194.  
  195.     UpdateEffects();   
  196.  
  197.     m_flNextBuzzTime = 0;
  198. #else
  199.     m_bMainPatientFlaggedForRemoval = false;
  200.  
  201.     RemoveAllHealTargets();
  202.  
  203.     if ( m_pUberTarget && GetTFPlayerOwner() ) {
  204.         m_pUberTarget->m_Shared.StopHealing( GetTFPlayerOwner(), HEALER_TYPE_BEAM );
  205.         m_pUberTarget = NULL;
  206.     }
  207. #endif
  208.  
  209.     m_bBuiltChargeThisFrame = false;
  210.  
  211.     ZoomOut();
  212. }
  213.  
  214. void CTFPaintballRifle::UpdateOnRemove( void )
  215. {
  216. #ifdef CLIENT_DLL
  217.     if ( m_pHealSoundManager )
  218.         m_pHealSoundManager->RemoveSound();
  219. #else
  220.     RemoveAllHealTargets();
  221. #endif
  222.  
  223.     BaseClass::UpdateOnRemove();
  224. }
  225.  
  226. medigun_charge_types CTFPaintballRifle::GetChargeType( void )
  227. {
  228.     int iChargeType = TF_CHARGE_INVULNERABLE;
  229.     CALL_ATTRIB_HOOK_INT( iChargeType, set_charge_type );
  230.     if ( iChargeType > TF_CHARGE_NONE && iChargeType < TF_CHARGE_COUNT )
  231.         return (medigun_charge_types)iChargeType;
  232.  
  233.     AssertMsg( 0, "Invalid charge type!\n" );
  234.     return TF_CHARGE_NONE;
  235. }
  236.  
  237. void CTFPaintballRifle::HandleZooms( void )
  238. {
  239.     // Get the owning player.
  240.     CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
  241.     if ( !pPlayer )
  242.         return;
  243.  
  244.     int bBlockZoom = 0;
  245.     CALL_ATTRIB_HOOK_INT( bBlockZoom, unimplemented_mod_sniper_no_charge );
  246.     if ( bBlockZoom > 0 )
  247.         return;
  248.  
  249.     // Unzoom if we're jumping or taunting.
  250.     if ( pPlayer->m_Shared.IsJumping() || pPlayer->m_Shared.InCond( TF_COND_TAUNTING ) )
  251.     {
  252.         if ( IsZoomed() )
  253.         {
  254.             ToggleZoom();
  255.         }
  256.  
  257.         //Don't rezoom in the middle of a taunt.
  258.         //ResetTimers();
  259.         return;
  260.     }
  261.  
  262.     if ( m_flUnzoomTime > 0 && gpGlobals->curtime > m_flUnzoomTime )
  263.     {
  264.         if ( m_bRezoomAfterShot )
  265.         {
  266.             ZoomOutIn();
  267.             m_bRezoomAfterShot = false;
  268.         }
  269.         else
  270.         {
  271.             ZoomOut();
  272.         }
  273.  
  274.         m_flUnzoomTime = -1;
  275.     }
  276.  
  277.     if ( m_flRezoomTime > 0 )
  278.     {
  279.         if ( gpGlobals->curtime > m_flRezoomTime )
  280.         {
  281.             ZoomIn();
  282.             m_flRezoomTime = -1;
  283.         }
  284.     }
  285.  
  286.     if ( pPlayer->ShouldHoldToZoom() )
  287.     {
  288.         if ( pPlayer->m_nButtons & IN_ATTACK2 )
  289.         {
  290.             if ( !IsZoomed() )
  291.             {
  292.                 if ( m_flNextSecondaryAttack <= gpGlobals->curtime )
  293.                 {
  294.                     // If we're in the process of rezooming, just cancel it
  295.                     if ( m_flRezoomTime > 0 || m_flUnzoomTime > 0 )
  296.                     {
  297.                         // Prevent them from rezooming in less time than they would have
  298.                         m_flNextSecondaryAttack = m_flRezoomTime + TF_WEAPON_SNIPERRIFLE_ZOOM_TIME;
  299.                         m_flRezoomTime = -1;
  300.                     }
  301.                     else
  302.                     {
  303.                         Zoom();
  304.                     }
  305.                 }
  306.  
  307.                 // Zoom();
  308.             }
  309.         }
  310.         else
  311.         {
  312.             if ( IsZoomed() )
  313.             {
  314.                 Zoom();
  315.             }
  316.         }
  317.     }
  318.     else
  319.     {
  320.         if ( (pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime) )
  321.         {
  322.             // If we're in the process of rezooming, just cancel it
  323.             if ( m_flRezoomTime > 0 || m_flUnzoomTime > 0 )
  324.             {
  325.                 // Prevent them from rezooming in less time than they would have
  326.                 m_flNextSecondaryAttack = m_flRezoomTime + TF_WEAPON_SNIPERRIFLE_ZOOM_TIME;
  327.                 m_flRezoomTime = -1;
  328.             }
  329.             else
  330.             {
  331.                 Zoom();
  332.             }
  333.         }
  334.     }
  335. }
  336.  
  337. float CTFPaintballRifle::OwnerMaxSpeedModifier( void )
  338. {
  339.     CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
  340.     if ( pPlayer && pPlayer->m_Shared.InCond( TF_COND_AIMING ) )
  341.     {
  342.         float flAimingMoveSpeed = 120.0f;
  343.         return flAimingMoveSpeed;
  344.     }
  345.  
  346.     return 0.0f;
  347. }
  348.  
  349. bool CTFPaintballRifle::CanHolster( void ) const
  350. {
  351.     CTFPlayer *pPlayer = GetTFPlayerOwner();
  352.     if ( pPlayer )
  353.     {
  354.         // don't allow us to holster this weapon if we're in the process of zooming and
  355.         // we've just fired the weapon (next primary attack is only 1.5 seconds after firing)
  356.         if ( (pPlayer->GetFOV() < pPlayer->GetDefaultFOV()) && (m_flNextPrimaryAttack > gpGlobals->curtime) )
  357.         {
  358.             return false;
  359.         }
  360.     }
  361.  
  362.     return BaseClass::CanHolster();
  363. }
  364.  
  365. bool CTFPaintballRifle::Holster(CBaseCombatWeapon *pSwitchingTo)
  366. {
  367. #ifdef CLIENT_DLL
  368.     if ( m_pHealSoundManager )
  369.     {
  370.         if ( !m_pHealSoundManager->IsSetupCorrectly() )
  371.         {
  372.             m_pHealSoundManager->RemoveSound();
  373.             delete m_pHealSoundManager;
  374.             m_pHealSoundManager = NULL;
  375.  
  376.             m_pHealSoundManager = new CTFHealSoundManager( GetTFPlayerOwner(), this );
  377.         }
  378.     }
  379.  
  380.     UpdateEffects();
  381.  
  382.     //ManageChargeEffect();
  383.  
  384. #else
  385.     if ( !GetTFPlayerOwner()->IsAlive() )
  386.         RemoveAllHealTargets();
  387. #endif
  388.  
  389.     CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  390.     if ( pPlayer && pPlayer->m_Shared.InCond( TF_COND_ZOOMED ) )
  391.     {
  392.         ZoomOut();
  393.     }
  394.  
  395.     return BaseClass::Holster( pSwitchingTo );
  396. }
  397.  
  398. bool CTFPaintballRifle::Deploy( void )
  399. {
  400. #ifdef CLIENT_DLL
  401.     //ManageChargeEffect();
  402.  
  403.         if ( m_pHealSoundManager )
  404.         {
  405.             if ( !m_pHealSoundManager->IsSetupCorrectly() )
  406.             {
  407.                 m_pHealSoundManager->RemoveSound();
  408.                 delete m_pHealSoundManager;
  409.                 m_pHealSoundManager = NULL;
  410.    
  411.                 m_pHealSoundManager = new CTFHealSoundManager( GetTFPlayerOwner(), this );
  412.             }
  413.         }
  414. #endif
  415.     return BaseClass::Deploy();
  416. }
  417.  
  418. void CTFPaintballRifle::ItemHolsterFrame( void )
  419. {
  420.     BaseClass::ItemHolsterFrame();
  421. #ifdef GAME_DLL
  422.     ApplyBackpackHealing();
  423. #else
  424. #if 0
  425.     m_pHealSoundManager->SetPatient( ToTFPlayer(m_hMainPatient.Get()) );
  426.     m_pHealSoundManager->SoundManagerThink();
  427. #endif
  428. #endif
  429.  
  430.     m_bBuiltChargeThisFrame = false;
  431.  
  432.     DrainCharge();
  433. }
  434.  
  435. void CTFPaintballRifle::ItemPostFrame( void )
  436. {
  437.     // Get the owning player.
  438.     CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
  439.     if ( !pPlayer )
  440.         return;
  441.  
  442.     //BaseClass::ItemPostFrame();
  443. #ifdef GAME_DLL
  444.     ApplyBackpackHealing();
  445. #else
  446. #if 0
  447.     m_pHealSoundManager->SetPatient( ToTFPlayer( m_hMainPatient.Get() ) );
  448.     m_pHealSoundManager->SoundManagerThink();
  449. #endif
  450. #endif
  451.  
  452.     m_bBuiltChargeThisFrame = false;
  453.    
  454.     if ( !IsZoomed() )
  455.         CheckReload();
  456.  
  457.     // Interrupt a reload.
  458.     if ( IsReloading() && Clip1() > 0 && (pPlayer->m_nButtons & IN_ATTACK) )
  459.     {
  460.         AbortReload();
  461.     }
  462.  
  463.     if ( !CanAttack() )
  464.     {
  465.         if ( IsZoomed() )
  466.         {
  467.             ToggleZoom();
  468.         }
  469.         return;
  470.     }
  471.  
  472.     HandleZooms();
  473.  
  474.     // Fire.
  475.     if ( pPlayer->m_nButtons & IN_ATTACK )
  476.     {
  477.         Fire( pPlayer );
  478.     }
  479.  
  480.     if ( pPlayer->m_nButtons & IN_ATTACK3 )
  481.         TertiaryAttack();
  482.  
  483.     // Idle.
  484.     if ( !((pPlayer->m_nButtons & IN_ATTACK) || (pPlayer->m_nButtons & IN_ATTACK2)) )
  485.     {
  486.         // No fire buttons down or reloading
  487.         if ( (!ReloadOrSwitchWeapons() && !IsReloading()) || IsZoomed() )
  488.         {
  489.             WeaponIdle();
  490.         }
  491.     }
  492.  
  493.     // Reload.
  494.     if ( !IsZoomed() )
  495.     {
  496.         if ( (pPlayer->m_nButtons & IN_RELOAD) && UsesClipsForAmmo1() )
  497.         {
  498.             Reload();
  499.         }
  500.  
  501.         if ( IsReloading() && IsZoomed() )
  502.         {
  503.             ToggleZoom();
  504.         }
  505.     }
  506. }
  507.  
  508. void CTFPaintballRifle::TertiaryAttack()
  509. {
  510.     //if ( !CanAttack() )
  511.     //  return;
  512.  
  513.     // Ensure they have a full charge
  514.     if ( m_flChargeLevel < GetMinChargeAmount() || m_bChargeRelease )
  515.     {
  516. #ifdef CLIENT_DLL
  517.         // Deny, buzz.
  518.         if ( gpGlobals->curtime >= m_flNextBuzzTime )
  519.         {
  520.             EmitSound( "Player.DenyWeaponSelection" );
  521.             m_flNextBuzzTime = gpGlobals->curtime + 0.5f; // Only buzz every so often.
  522.         }
  523. #endif
  524.         return;
  525.     }
  526.  
  527. #ifdef GAME_DLL
  528.  
  529.     CTFPlayer *pOwner = assert_cast<CTFPlayer *>(GetOwner());
  530.  
  531.     trace_t tr;
  532.     UTIL_TraceLine( pOwner->EyePosition(), pOwner->EyePosition() + pOwner->EyeDirection3D() * MAX_TRACE_LENGTH, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
  533.     if ( tr.fraction >= 1 )
  534.         return;
  535.  
  536.     CTFPlayer *pTarget = ToTFPlayer( tr.m_pEnt );
  537.     if ( !pTarget ) {
  538.         //DevMsg( "Could not Uber: pEnt was not a player.\n" );
  539.         return;
  540.     }
  541.     if ( pTarget->IsEnemy( pOwner ) ) {
  542.         //DevMsg( "Could not Uber: player was an enemy.\n" );
  543.         return;
  544.     }
  545.  
  546.     // Stop the player shootin' for a lil while
  547.     m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
  548.     m_bChargeRelease = true;
  549.     SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  550.     pOwner->NoteWeaponFired( this );
  551.  
  552.     pTarget->m_Shared.Heal( pOwner, 0 );
  553.     pTarget->m_Shared.RecalculateChargeEffects();
  554.     m_pUberTarget = pTarget;
  555.  
  556.     // Make weaponbase load our secondary projectile type!
  557.     // m_iWeaponMode = TF_WEAPON_SECONDARY_MODE;
  558.  
  559.     //CTF_GameStats.Event_PlayerInvulnerable( pOwner );
  560.     // Handled by the generator
  561.     //pOwner->m_Shared.RecalculateChargeEffects();
  562.  
  563.     pOwner->SpeakConceptIfAllowed( MP_CONCEPT_MEDIC_CHARGEDEPLOYED );
  564.  
  565.     pTarget->SpeakConceptIfAllowed( MP_CONCEPT_HEALTARGET_CHARGEDEPLOYED ); //MP_CONCEPT_PLAYER_BATTLECRY //MP_CONCEPT_PLAYER_TAUNT MP_CONCEPT_HEALTARGET_CHARGEDEPLOYED;
  566.  
  567.     IGameEvent *event = gameeventmanager->CreateEvent( "player_chargedeployed" );
  568.     if ( event )
  569.     {
  570.         event->SetInt( "userid", pOwner->GetUserID() );
  571.  
  572.         gameeventmanager->FireEvent( event );
  573.     }
  574. #endif
  575. }
  576.  
  577. bool CTFPaintballRifle::Lower( void )
  578. {
  579.     if ( BaseClass::Lower() )
  580.     {
  581.         if ( IsZoomed() )
  582.         {
  583.             ToggleZoom();
  584.         }
  585.  
  586.         return true;
  587.     }
  588.  
  589.     return false;
  590. }
  591.  
  592. //-----------------------------------------------------------------------------
  593. // Purpose: Secondary attack.
  594. //-----------------------------------------------------------------------------
  595. void CTFPaintballRifle::Zoom( void )
  596. {
  597.     // Don't allow the player to zoom in while jumping
  598.     CTFPlayer *pPlayer = GetTFPlayerOwner();
  599.     if ( pPlayer && pPlayer->m_Shared.IsJumping() )
  600.     {
  601.         if ( pPlayer->GetFOV() >= 75 )
  602.             return;
  603.     }
  604.  
  605.     ToggleZoom();
  606.  
  607.     // at least 0.1 seconds from now, but don't stomp a previous value
  608.     m_flNextPrimaryAttack = Max( m_flNextPrimaryAttack.Get(), gpGlobals->curtime + 0.1f );
  609.     m_flNextSecondaryAttack = gpGlobals->curtime + TF_WEAPON_SNIPERRIFLE_ZOOM_TIME;
  610. }
  611.  
  612. void CTFPaintballRifle::ZoomOutIn( void )
  613. {
  614.     ZoomOut();
  615.  
  616.     CTFPlayer *pPlayer = GetTFPlayerOwner();
  617.     if ( pPlayer && pPlayer->ShouldAutoRezoom() )
  618.     {
  619.         m_flRezoomTime = gpGlobals->curtime + 0.1f;
  620.     }
  621.     else
  622.     {
  623.         m_flNextSecondaryAttack = gpGlobals->curtime + 0.1f;
  624.     }
  625. }
  626.  
  627. void CTFPaintballRifle::ZoomIn( void )
  628. {
  629.     // Start aiming.
  630.     CTFPlayer *pPlayer = GetTFPlayerOwner();
  631.  
  632.     if ( !pPlayer )
  633.         return;
  634.  
  635.     if ( !HasPrimaryAmmoToFire() )
  636.         return;
  637.  
  638.     // Interrupt a reload.
  639.     if ( IsReloading() && Clip1() > 0 )
  640.     {
  641.         AbortReload();
  642.     }
  643.  
  644.     BaseClass::ZoomIn();
  645.  
  646.     pPlayer->m_Shared.AddCond( TF_COND_AIMING );
  647.     pPlayer->TeamFortress_SetSpeed();
  648. }
  649.  
  650. bool CTFPaintballRifle::IsZoomed( void )
  651. {
  652.     CTFPlayer *pPlayer = GetTFPlayerOwner();
  653.  
  654.     if ( pPlayer )
  655.     {
  656.         return pPlayer->m_Shared.InCond( TF_COND_ZOOMED );
  657.     }
  658.  
  659.     return false;
  660. }
  661.  
  662. void CTFPaintballRifle::ZoomOut( void )
  663. {
  664.     BaseClass::ZoomOut();
  665.  
  666.     // Stop aiming
  667.     CTFPlayer *pPlayer = GetTFPlayerOwner();
  668.  
  669.     if ( !pPlayer )
  670.         return;
  671.  
  672.     pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
  673.     pPlayer->TeamFortress_SetSpeed();
  674.  
  675.     // if we are thinking about zooming, cancel it
  676.     m_flUnzoomTime = -1;
  677.     m_flRezoomTime = -1;
  678.     m_bRezoomAfterShot = false;
  679. }
  680.  
  681. void CTFPaintballRifle::Fire( CTFPlayer *pPlayer )
  682. {
  683.     if ( m_flNextPrimaryAttack > gpGlobals->curtime )
  684.         return;
  685.  
  686.     // Check the ammo.
  687.     if ( !HasPrimaryAmmoToFire() )
  688.     {
  689.         HandleFireOnEmpty();
  690.         return;
  691.     }
  692.  
  693.     float iScopedFireDelay = GetTFWpnData().GetWeaponData( TF_WEAPON_SECONDARY_MODE ).m_flTimeFireDelay;
  694.     CALL_ATTRIB_HOOK_FLOAT( iScopedFireDelay, mult_postfiredelay );
  695.    
  696.     // Shoot
  697.     PrimaryAttack();
  698.  
  699.     if ( iScopedFireDelay != 0.0f && IsZoomed() )
  700.     {
  701.         CALL_ATTRIB_HOOK_FLOAT( iScopedFireDelay, mult_postfiredelay_scoped );
  702.         m_flNextPrimaryAttack = gpGlobals->curtime + iScopedFireDelay;
  703.     }
  704.  
  705.     int iNoScope = 0;
  706.     CALL_ATTRIB_HOOK_INT( iNoScope, mod_no_scope );
  707.  
  708.     if ( !iNoScope && (IsZoomed() && !pPlayer->ShouldHoldToZoom()) )
  709.     {
  710.         // If we have more bullets, zoom out, play the bolt animation and zoom back in
  711.         if ( HasPrimaryAmmoToFire() )
  712.         {
  713.             SetRezoom( true, 0.5f );    // zoom out in 0.5 seconds, then rezoom
  714.         }
  715.         else
  716.         {
  717.             //just zoom out
  718.             SetRezoom( false, 0.5f );   // just zoom out in 0.5 seconds
  719.         }
  720.     }
  721.     else
  722.     {
  723.         // Prevent primary fire preventing zooms
  724.         // m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  725.         m_flNextSecondaryAttack = gpGlobals->curtime + 0.05f;
  726.     }
  727. }
  728.  
  729. void CTFPaintballRifle::SetRezoom( bool bRezoom, float flDelay )
  730. {
  731.     m_flUnzoomTime = gpGlobals->curtime + flDelay;
  732.  
  733.     m_bRezoomAfterShot = bRezoom;
  734. }
  735.  
  736. void CTFPaintballRifle::AddCharge( float flAmount )
  737. {
  738.     float flChargeRate = 1.0f;
  739.     CALL_ATTRIB_HOOK_FLOAT( flChargeRate, mult_medigun_uberchargerate );
  740.     CALL_ATTRIB_HOOK_FLOAT( flChargeRate, mult_medigun_uberchargerate_wearer );
  741.     if ( !flChargeRate ) // Can't earn uber.
  742.         return;
  743.  
  744.     float flNewLevel = Min( m_flChargeLevel + flAmount, 1.0f );
  745.     flNewLevel = Max( flNewLevel, 0.0f );
  746.  
  747. #ifdef GAME_DLL
  748.     bool bSpeak = (flNewLevel >= GetMinChargeAmount() && m_flChargeLevel < GetMinChargeAmount());
  749. #endif
  750.     m_flChargeLevel = flNewLevel;
  751. #ifdef GAME_DLL
  752.     if ( bSpeak )
  753.     {
  754.         CTFPlayer *pPlayer = GetTFPlayerOwner();
  755.         if ( pPlayer )
  756.         {
  757.             pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_MEDIC_CHARGEREADY );
  758.         }
  759.     }
  760. #endif
  761. }
  762.  
  763. void CTFPaintballRifle::DrainCharge( void )
  764. {
  765.     if ( !m_bChargeRelease )
  766.         return;
  767.  
  768.     CTFPlayer *pOwner = GetTFPlayerOwner();
  769.     if ( !pOwner )
  770.         return;
  771.  
  772.     // If we're in charge release mode, drain our charge.
  773.     float flUberTime = weapon_medigun_chargerelease_rate.GetFloat();
  774.     CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pOwner, flUberTime, add_uber_time );
  775.     CALL_ATTRIB_HOOK_FLOAT( flUberTime, add_uber_time_active );
  776.  
  777.     float flChargeAmount = gpGlobals->frametime / flUberTime;
  778.  
  779.     m_flChargeLevel = Max( m_flChargeLevel - flChargeAmount, 0.0f );
  780.     if ( !m_flChargeLevel )
  781.     {
  782.         m_bChargeRelease = false;
  783. #ifdef GAME_DLL
  784.         if ( m_pUberTarget )
  785.         {
  786.             m_pUberTarget->m_Shared.StopHealing( pOwner, HEALER_TYPE_BEAM );
  787.             m_pUberTarget->m_Shared.RecalculateChargeEffects();
  788.         }
  789.  
  790.         pOwner->m_Shared.RecalculateChargeEffects();
  791. #endif
  792.     }
  793. }
  794.  
  795. void CTFPaintballRifle::BuildUberForTarget( CBaseEntity *pTarget, bool bMultiTarget /*= false*/ )
  796. {
  797.     if ( m_bBuiltChargeThisFrame )
  798.         return;
  799.  
  800.     CTFPlayer *pPatient = ToTFPlayer( pTarget );
  801.     // Charge up our power if we're not releasing it, and our target
  802.     // isn't receiving any benefit from our healing. (what da heck does this part mean? - hogyn)
  803.     if ( !m_bChargeRelease )
  804.     {
  805.         CTFPlayer *pOwner = GetTFPlayerOwner();
  806.  
  807.         if ( weapon_medigun_charge_rate.GetFloat() )
  808.         {
  809.             int iBoostMax = floor( pPatient->m_Shared.GetMaxBuffedHealth() * 0.95f );
  810.             //float flChargeAmount = flAmount / (tf2c_medicgl_health_to_uber_exchange_rate.GetFloat() * 100.0f);//weapon_medigun_charge_rate.GetFloat();
  811.             float flChargeAmount;
  812.  
  813.             flChargeAmount = gpGlobals->frametime / weapon_medigun_charge_rate.GetFloat();
  814.  
  815.             bool bInSetup = (TFGameRules() && TFGameRules()->InSetup() &&
  816. #ifdef GAME_DLL
  817.                 TFGameRules()->GetActiveRoundTimer() &&
  818. #endif
  819.                 tf2c_medigun_setup_uber.GetBool());
  820.  
  821.             // We can optionally skip this part since we already have a reduced overheal rate that's reflected in flAmount already.
  822.             if ( pPatient->GetHealth() >= pPatient->GetMaxHealth() && !bInSetup )
  823.             {
  824.                 CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pOwner, flChargeAmount, mult_medigun_overheal_uberchargerate );
  825.             }
  826.  
  827.             // On the gun we're using
  828.             CALL_ATTRIB_HOOK_FLOAT( flChargeAmount, mult_medigun_uberchargerate );
  829.  
  830.             // On the Healer themselves
  831.             CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pOwner, flChargeAmount, mult_medigun_uberchargerate_wearer );
  832.  
  833.             if ( bInSetup )
  834.             {
  835.                 // Build charge at an increased rate during setup.
  836.                 flChargeAmount *= 3.0f;
  837.             }
  838.             else if ( pPatient->GetHealth() >= iBoostMax )
  839.             {
  840.                 // Reduced charge for healing fully healed guys.
  841.                 flChargeAmount *= 0.5f;
  842.             }
  843.  
  844.             // Speed up charge rate when under minicrit or crit buffs.
  845.             if ( tf2c_medigun_critboostable.GetBool() )
  846.             {
  847.                 if ( pOwner->m_Shared.IsCritBoosted() )
  848.                 {
  849.                     flChargeAmount *= 3.0f;
  850.                 }
  851.                 else if ( pOwner->m_Shared.InCond( TF_COND_DAMAGE_BOOST ) || IsWeaponDamageBoosted() )
  852.                 {
  853.                     flChargeAmount *= 1.35f;
  854.                 }
  855.             }
  856.  
  857.             //if (pOwner->m_Shared.InCond(TF_COND_CIV_SPEEDBUFF))
  858.             //{
  859.             //  flChargeAmount *= TF2C_HASTE_UBER_FACTOR;
  860.             //}
  861.  
  862.             // In 4team, speed up charge rate to make up for smaller teams and decreased survivability.
  863.             if ( TFGameRules() && TFGameRules()->IsFourTeamGame() )
  864.             {
  865.                 flChargeAmount *= tf2c_medigun_4team_uber_rate.GetFloat();
  866.             }
  867.  
  868.             // Reduce charge rate when healing someone already being healed.
  869.             int iTotalHealers = pPatient->m_Shared.GetNumHumanHealers();
  870.             if ( !bInSetup && iTotalHealers > 1 )
  871.             {
  872.                 flChargeAmount /= (float)iTotalHealers;
  873.             }
  874.  
  875.             // Build rate bonus stacks
  876. #ifdef GAME_DLL
  877.             CheckAndExpireStacks();
  878. #endif
  879.             flChargeAmount *= 1.0f + GetUberRateBonus();
  880.  
  881.             float flNewLevel = Min( m_flChargeLevel + flChargeAmount, 1.0f );
  882.  
  883.             bool bSpeak = (flNewLevel >= GetMinChargeAmount() && m_flChargeLevel < GetMinChargeAmount());
  884.             m_flChargeLevel = flNewLevel;
  885.  
  886.             if ( bSpeak )
  887.             {
  888. #ifdef GAME_DLL
  889.                 pOwner->SpeakConceptIfAllowed( MP_CONCEPT_MEDIC_CHARGEREADY );
  890. #endif
  891.             }
  892.  
  893.             m_bBuiltChargeThisFrame = true;
  894.         }
  895.     }
  896. }
  897.  
  898. #ifdef GAME_DLL
  899. void CTFPaintballRifle::HitAlly( CBaseEntity *pEntity )
  900. {
  901.     CTFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );
  902.     CTFPlayer *pPlayer = ToTFPlayer( pEntity );
  903.  
  904.     //if ( pOwner->GetMedigun() )
  905.     //{
  906.     //  pOwner->GetMedigun()->AddBackpackPatient( pPlayer );
  907.     //}
  908.  
  909.     // Play the sound for the owner at the owner's ears, and for everyone else at the recipient
  910.     CPASFilter filter( pPlayer->GetAbsOrigin() );
  911.     if ( pOwner )
  912.     {
  913.         // Not directly on/in our ears but 10 units in the direction of our recipient.
  914.         Vector covector = (pPlayer->GetAbsOrigin() - pOwner->EyePosition());
  915.         float flMaxDist = covector.Length();
  916.         Vector ownerEarPos = pOwner->EyePosition() + covector.Normalized() * min( 128.0f, flMaxDist );
  917.         CSingleUserRecipientFilter singleFilter( pOwner );
  918.         pOwner->EmitSound( singleFilter, -1, "HealGrenade.Success", &ownerEarPos );
  919.     }
  920.  
  921.     CSingleUserRecipientFilter patientFilter( pPlayer );
  922.     pPlayer->EmitSound( patientFilter, pPlayer->entindex(), "HealGrenade.Success" );
  923.  
  924.     float flDuration = 0;
  925.     CALL_ATTRIB_HOOK_FLOAT( flDuration, marked_target_autoheal_duration );
  926.     if ( flDuration > 0 )
  927.         AddHealTarget( pPlayer, flDuration );
  928.  
  929.     // Do the actual insta-healing last so that the heal progress sound manager has the right old/new health values.
  930.     int iHealAmount = 0;
  931.     CALL_ATTRIB_HOOK_INT( iHealAmount, apply_heal_explosion );
  932.     CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetOwnerEntity(), iHealAmount, mult_medigun_healrate );
  933.     if ( iHealAmount )
  934.     {
  935.         float flBonusHealthDuration = 0.0f;
  936.         CALL_ATTRIB_HOOK_FLOAT( flBonusHealthDuration, marked_target_bonusheal_duration );
  937.         pPlayer->m_Shared.AddBurstHealer( pOwner, iHealAmount, flBonusHealthDuration > 0 ? TF_COND_TAKEBONUSHEALING : TF_COND_INVALID, flBonusHealthDuration );
  938.  
  939.         // For the sake of attribution of assists etc., at a "zero healer" for a short period.
  940.         pPlayer->m_Shared.HealTimed( pOwner, 0, 3, true );
  941.     }
  942.  
  943.     OnDirectHit( pPlayer );
  944. }
  945.  
  946. void CTFPaintballRifle::RemoveAllHealTargets( void )
  947. {
  948.     int iCount = m_vAutoHealTargets.Count(); // Need to cache this first because it'll change throughout the for loop otherwise.
  949.     for ( int i = 0; i < iCount; i++ )
  950.     {
  951.         RemoveHealTarget( ToTFPlayer( m_vAutoHealTargets[i] ) );
  952.     }
  953. }
  954.  
  955. void CTFPaintballRifle::AddHealTarget( CTFPlayer *pPlayer, float flDuration )
  956. {
  957.     // Reset the timer
  958.     if ( m_vAutoHealTargets.HasElement( pPlayer ) )
  959.     {
  960.         m_vTargetRemoveTime[m_vAutoHealTargets.Find( pPlayer )] = gpGlobals->curtime + flDuration;
  961.     }
  962.     // Add to list
  963.     else
  964.     {
  965.         m_vAutoHealTargets.AddToTail( pPlayer );
  966.         m_vTargetRemoveTime.AddToTail( gpGlobals->curtime + flDuration );
  967.         m_vTargetsActive.AddToTail( false );
  968.     }
  969.  
  970.     m_hMainPatient = pPlayer;
  971.     m_iMainPatientHealthLast = pPlayer->GetHealth();
  972. }
  973.  
  974. void CTFPaintballRifle::RemoveHealTarget( CTFPlayer *pPlayer )
  975. {
  976.     CTFPlayer *pOwner = GetTFPlayerOwner();
  977.     if ( !pOwner )
  978.         return;
  979.  
  980.     if(m_hMainPatient.Get() == pPlayer)
  981.     {
  982.         //m_hMainPatient = NULL;
  983.         // Set Main patient to null next update.
  984.         m_bMainPatientFlaggedForRemoval = true;
  985.     }
  986.  
  987.     pPlayer->m_Shared.StopHealing( pOwner, HEALER_TYPE_BEAM );
  988.  
  989.     int iIndex = m_vAutoHealTargets.Find( pPlayer );
  990.     m_vAutoHealTargets.Remove( iIndex );
  991.     m_vTargetRemoveTime.Remove( iIndex );
  992.     m_vTargetsActive.Remove( iIndex );
  993. }
  994.  
  995. void CTFPaintballRifle::ApplyBackpackHealing( void )
  996. {
  997.     CTFPlayer *pOwner = GetTFPlayerOwner();
  998.     if ( !pOwner )
  999.         return;
  1000.  
  1001.     if( m_bMainPatientFlaggedForRemoval )
  1002.     {
  1003.         m_hMainPatient = NULL;
  1004.         m_bMainPatientFlaggedForRemoval = false;
  1005.     }
  1006.  
  1007.     FOR_EACH_VEC(m_vAutoHealTargets, i)
  1008.     {
  1009.         CTFPlayer *pPlayer = ToTFPlayer( m_vAutoHealTargets[i] );
  1010.         if ( !pPlayer )
  1011.             continue;
  1012.  
  1013.         float flRange2 = pPlayer->GetAbsOrigin().DistToSqr(pOwner->GetAbsOrigin());
  1014.         float flMaxRange2 = PAINTBALL_BACKPACK_RANGE_SQ;
  1015.         CALL_ATTRIB_HOOK_FLOAT( flMaxRange2, mult_backpack_range );
  1016.         CALL_ATTRIB_HOOK_FLOAT( flMaxRange2, mult_weapon_range );
  1017.  
  1018.         if ( gpGlobals->curtime > m_vTargetRemoveTime[i] || flRange2 > flMaxRange2 )
  1019.         {
  1020.             RemoveHealTarget( pPlayer );
  1021.             continue;
  1022.         }
  1023.        
  1024.         // Do we need to initiate a heal? Do so here:
  1025.         if ( !m_vTargetsActive[i] )
  1026.         {
  1027.             pPlayer->m_Shared.Heal( pOwner, GetHealRate() );
  1028.             m_vTargetsActive[i] = true;
  1029.         }
  1030.     }
  1031. }
  1032.  
  1033. float CTFPaintballRifle::GetHealRate( void )
  1034. {
  1035.     float flBaseHealRate = 0;
  1036.     CALL_ATTRIB_HOOK_FLOAT( flBaseHealRate, marked_target_autoheal_rate );
  1037.     // TODO call extra heal rate attribs here
  1038.     return flBaseHealRate;
  1039. }
  1040.  
  1041. void CTFPaintballRifle::OnDirectHit( CTFPlayer *pPatient )
  1042. {
  1043.     // Build direct-hit Uber based on our firerate
  1044.  
  1045.     CTFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );
  1046.  
  1047.     if ( !m_bChargeRelease && pOwner)
  1048.     {
  1049.         if ( weapon_medigun_charge_rate.GetFloat() && pPatient->GetHealth() < pPatient->GetMaxHealth() )
  1050.         {
  1051.             int iBoostMax = floor( pPatient->m_Shared.GetMaxBuffedHealth() * 0.95f );
  1052.             //float flChargeAmount = flAmount / (tf2c_medicgl_health_to_uber_exchange_rate.GetFloat() * 100.0f);//weapon_medigun_charge_rate.GetFloat();
  1053.             float flChargeAmount;
  1054.  
  1055.             // Medigun healing for T seconds, where T is the fire interval -> 1 direct hit's uber build amount
  1056.             flChargeAmount = GetFireRate() / (weapon_medigun_charge_rate.GetFloat());
  1057.  
  1058.             bool bInSetup = (TFGameRules() && TFGameRules()->InSetup() &&
  1059. #ifdef GAME_DLL
  1060.                 TFGameRules()->GetActiveRoundTimer() &&
  1061. #endif
  1062.                 tf2c_medigun_setup_uber.GetBool());
  1063.  
  1064.             // We can optionally skip this part since we already have a reduced overheal rate that's reflected in flAmount already.
  1065.             if ( pPatient->GetHealth() >= pPatient->GetMaxHealth() && !bInSetup )
  1066.             {
  1067.                 CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pOwner, flChargeAmount, mult_medigun_overheal_uberchargerate );
  1068.             }
  1069.  
  1070.             // On the gun we're using
  1071.             CALL_ATTRIB_HOOK_FLOAT( flChargeAmount, mult_medigun_uberchargerate );
  1072.  
  1073.             // On the Healer themselves
  1074.             CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pOwner, flChargeAmount, mult_medigun_uberchargerate_wearer );
  1075.  
  1076.             if ( bInSetup )
  1077.             {
  1078.                 // Build charge at an increased rate during setup.
  1079.                 flChargeAmount *= 3.0f;
  1080.             }
  1081.             else if ( pPatient->GetHealth() >= iBoostMax )
  1082.             {
  1083.                 // Reduced charge for healing fully healed guys.
  1084.                 flChargeAmount *= 0.5f;
  1085.             }
  1086.  
  1087.             // Speed up charge rate when under minicrit or crit buffs.
  1088.             if ( tf2c_medigun_critboostable.GetBool() )
  1089.             {
  1090.                 if ( pOwner->m_Shared.IsCritBoosted() )
  1091.                 {
  1092.                     flChargeAmount *= 3.0f;
  1093.                 }
  1094.                 else if ( pOwner->m_Shared.InCond( TF_COND_DAMAGE_BOOST ) || IsWeaponDamageBoosted() )
  1095.                 {
  1096.                     flChargeAmount *= 1.35f;
  1097.                 }
  1098.             }
  1099.  
  1100.             //if (pOwner->m_Shared.InCond(TF_COND_CIV_SPEEDBUFF))
  1101.             //{
  1102.             //  flChargeAmount *= TF2C_HASTE_UBER_FACTOR;
  1103.             //}
  1104.  
  1105.             // In 4team, speed up charge rate to make up for smaller teams and decreased survivability.
  1106.             if ( TFGameRules() && TFGameRules()->IsFourTeamGame() )
  1107.             {
  1108.                 flChargeAmount *= tf2c_medigun_4team_uber_rate.GetFloat();
  1109.             }
  1110.  
  1111.             // Reduce charge rate when healing someone already being healed.
  1112.             int iTotalHealers = pPatient->m_Shared.GetNumHumanHealers();
  1113.             if ( !bInSetup && iTotalHealers > 1 )
  1114.             {
  1115.                 flChargeAmount /= (float)iTotalHealers;
  1116.             }
  1117.  
  1118.             // Build rate bonus stacks
  1119. #ifdef GAME_DLL
  1120.             CheckAndExpireStacks();
  1121. #endif
  1122.             flChargeAmount *= 1.0f + GetUberRateBonus();
  1123.  
  1124.             float flNewLevel = Min( m_flChargeLevel + flChargeAmount, 1.0f );
  1125.  
  1126.             bool bSpeak = (flNewLevel >= GetMinChargeAmount() && m_flChargeLevel < GetMinChargeAmount());
  1127.             m_flChargeLevel = flNewLevel;
  1128.  
  1129.             if ( bSpeak )
  1130.             {
  1131. #ifdef GAME_DLL
  1132.                 pOwner->SpeakConceptIfAllowed( MP_CONCEPT_MEDIC_CHARGEREADY );
  1133. #endif
  1134.             }
  1135.         }
  1136.     }
  1137.  
  1138. #ifdef GAME_DLL
  1139.     IGameEvent* event = gameeventmanager->CreateEvent( "patient_healed_notify" );
  1140.     if ( event )
  1141.     {
  1142.         event->SetInt( "userid", pPatient->entindex() );
  1143.         event->SetInt( "healerid", pOwner->entindex() );
  1144.         gameeventmanager->FireEvent( event );
  1145.     }
  1146. #endif
  1147.  
  1148.     m_hMainPatient = pPatient;
  1149.     m_iMainPatientHealthLast = pPatient->GetHealth();
  1150.     m_bMainPatientFlaggedForRemoval = true;
  1151. }
  1152.  
  1153. #else
  1154.  
  1155. void CTFPaintballRifle::UpdateEffects( void )
  1156. {
  1157.     CTFPlayer *pOwner = GetTFPlayerOwner();
  1158.  
  1159.     // Find all the targets we've stopped healing.
  1160.     int i, j, c, x;
  1161.     bool bStillBPHealing[MAX_PLAYERS];
  1162.     for ( i = 0, c = m_hBackpackTargetEffects.Count(); i < c; i++ )
  1163.     {
  1164.         bStillBPHealing[i] = false;
  1165.  
  1166.         // Are we still healing this target?
  1167.         for ( j = 0, x = m_vAutoHealTargets.Count(); j < x; j++ )
  1168.         {
  1169.             if ( m_vAutoHealTargets[j] &&
  1170.                 m_vAutoHealTargets[j] == m_hBackpackTargetEffects[i].pTarget &&
  1171.                 ShouldShowEffectForPlayer( ToTFPlayer( m_vAutoHealTargets[j] ) ))
  1172.             {
  1173.                 bStillBPHealing[i] = true;
  1174.                 break;
  1175.             }
  1176.         }
  1177.     }
  1178.  
  1179.     // Now remove all the dead effects.
  1180.     for ( i = m_hBackpackTargetEffects.Count() - 1; i >= 0; i-- )
  1181.     {
  1182.         if ( !bStillBPHealing[i] )
  1183.         {
  1184.             pOwner->ParticleProp()->StopEmission( m_hBackpackTargetEffects[i].pEffect );
  1185.             pOwner->ParticleProp()->StopEmission( m_hTargetOverheadEffects[i].pEffect );
  1186.             m_hBackpackTargetEffects.Remove( i );
  1187.             m_hTargetOverheadEffects.Remove( i );
  1188.             CPASFilter filter( GetAbsOrigin() );
  1189.             EmitSound_t eSoundParams;
  1190.             eSoundParams.m_pSoundName = BP_SOUND_HEALOFF;
  1191.             eSoundParams.m_flVolume = 0.35f;
  1192.             eSoundParams.m_nFlags |= SND_CHANGE_VOL;
  1193.             EmitSound( filter, entindex(), eSoundParams );
  1194.         }
  1195.     }
  1196.  
  1197.     // Now add any new targets.
  1198.     for ( i = 0, c = m_vAutoHealTargets.Count(); i < c; i++ )
  1199.     {
  1200.         C_TFPlayer *pTarget = ToTFPlayer( m_vAutoHealTargets[i].Get() );
  1201.         if ( !pTarget || !ShouldShowEffectForPlayer( pTarget ) )
  1202.             continue;
  1203.  
  1204.         // Loops through the healing targets, and make sure we have an effect for each of them.
  1205.         bool bHaveEffect = false;
  1206.         for ( j = 0, x = m_hBackpackTargetEffects.Count(); j < x; j++ )
  1207.         {
  1208.             if ( m_hBackpackTargetEffects[j].pTarget == pTarget )
  1209.             {
  1210.                 bHaveEffect = true;
  1211.                 break;
  1212.             }
  1213.         }
  1214.  
  1215.         if ( bHaveEffect )
  1216.             continue;
  1217.  
  1218.         const char *pszEffectName = "backpack_beam";
  1219.         //const char *pszEffectName = ConstructTeamParticle( "overhealer_%s_beam", GetTeamNumber() );
  1220.         CNewParticleEffect *pEffect = pOwner->ParticleProp()->Create( pszEffectName, PATTACH_POINT_FOLLOW, "flag" );
  1221.         pOwner->ParticleProp()->AddControlPoint( pEffect, 1, pTarget, PATTACH_ABSORIGIN_FOLLOW, NULL, Vector( 0, 0, 50 ) );
  1222.  
  1223.         int iIndex = m_hBackpackTargetEffects.AddToTail();
  1224.         m_hBackpackTargetEffects[iIndex].pTarget = pTarget;
  1225.         m_hBackpackTargetEffects[iIndex].pEffect = pEffect;
  1226.         m_hBackpackTargetEffects[iIndex].hOwner = pOwner;
  1227.  
  1228.         const char *pszEffectNameOverhead = BP_PARTICLE_ACTIVE;
  1229.         CNewParticleEffect *pEffectOverhead = pOwner->ParticleProp()->Create( pszEffectNameOverhead, PATTACH_ABSORIGIN_FOLLOW );
  1230.         pOwner->ParticleProp()->AddControlPoint( pEffectOverhead, 1, pTarget, PATTACH_ABSORIGIN_FOLLOW, NULL, Vector( 0, 0, 60 ) ); // Position it above his head.
  1231.  
  1232.         int iIndexAdd = m_hTargetOverheadEffects.AddToTail();
  1233.         m_hTargetOverheadEffects[iIndexAdd].pTarget = pTarget;
  1234.         m_hTargetOverheadEffects[iIndexAdd].pEffect = pEffectOverhead;
  1235.         m_hTargetOverheadEffects[iIndexAdd].hOwner = pOwner;
  1236.  
  1237.         CPASFilter filter( GetAbsOrigin() );
  1238.         EmitSound_t eSoundParams;
  1239.         eSoundParams.m_pSoundName = BP_SOUND_HEALON;
  1240.         eSoundParams.m_flVolume = 0.65f;
  1241.         eSoundParams.m_nFlags |= SND_CHANGE_VOL;
  1242.         EmitSound( filter, entindex(), eSoundParams );
  1243.     }
  1244. }
  1245.  
  1246. bool CTFPaintballRifle::ShouldShowEffectForPlayer( C_TFPlayer *pPlayer )
  1247. {
  1248.     // Don't give away cloaked spies.
  1249.     // FIXME: Is the latter part of this check necessary?
  1250.     if ( pPlayer->m_Shared.IsStealthed() || pPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) )
  1251.         return false;
  1252.  
  1253.     // Don't show the effect for disguised spies unless they're the same color.
  1254.     if ( GetLocalPlayerTeam() >= FIRST_GAME_TEAM && pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) && (!pPlayer->m_Shared.DisguiseFoolsTeam( GetTeamNumber() )) )
  1255.         return false;
  1256.  
  1257.     return true;
  1258. }
  1259.  
  1260. void CTFPaintballRifle::OnDataChanged( DataUpdateType_t updateType )
  1261. {
  1262.     BaseClass::OnDataChanged( updateType );
  1263.  
  1264.     if ( m_bBackpackTargetsParity != m_bOldBackpackTargetsParity )
  1265.     {
  1266.         m_bUpdateBackpackTargets = true;
  1267.     }
  1268.  
  1269.     if ( m_bMainTargetParityOld != m_bMainTargetParity && m_pHealSoundManager )
  1270.     {
  1271.         if ( !m_pHealSoundManager->IsSetupCorrectly() )
  1272.         {
  1273.             m_pHealSoundManager->RemoveSound();
  1274.             delete m_pHealSoundManager;
  1275.             m_pHealSoundManager = NULL;
  1276.  
  1277.             m_pHealSoundManager = new CTFHealSoundManager( GetTFPlayerOwner(), this );
  1278.         }
  1279.  
  1280.         // Let the heal sound manager know of the recorded health from before the healing was done.
  1281. #if 0
  1282.         m_pHealSoundManager->SetPatient( ToTFPlayer( m_hMainPatient ) );
  1283.         if ( m_hMainPatient )
  1284.             m_pHealSoundManager->SetLastPatientHealth( m_iMainPatientHealthLast );
  1285. #endif
  1286.        
  1287.     }
  1288.  
  1289.     if ( m_bUpdateBackpackTargets )
  1290.     {
  1291.         UpdateEffects();
  1292.  
  1293.         m_bUpdateBackpackTargets = false;
  1294.     }
  1295. }
  1296.  
  1297. void CTFPaintballRifle::OnPreDataChanged( DataUpdateType_t updateType )
  1298. {
  1299.     BaseClass::OnPreDataChanged( updateType );
  1300.  
  1301.     m_bOldBackpackTargetsParity = m_bBackpackTargetsParity;
  1302.     m_bMainTargetParityOld = m_bMainTargetParity;
  1303. }
  1304.  
  1305. #ifdef TF2C_BETA // public doesnt need this. not leaking cvars and CTFPatientHealthbarPanel
  1306. void CTFPaintballRifle::UpdateRecentPatientHealthbar( C_TFPlayer *pPatient )
  1307. {
  1308.     pPatient->CreateOverheadHealthbar();
  1309. }
  1310.  
  1311. void CTFPaintballRifle::FireGameEvent( IGameEvent* pEvent )
  1312. {
  1313.     //if ( tf2c_medicgl_show_patient_health.GetBool() )
  1314.     {
  1315.         if ( !strcmp( "patient_healed_notify", pEvent->GetName() ) )
  1316.         {
  1317.             int iUserID = pEvent->GetInt( "userid" );
  1318.             int iHealerID = pEvent->GetInt( "healerid" );
  1319.             CTFPlayer *pPatient = dynamic_cast<CTFPlayer *>(ClientEntityList().GetEnt( iUserID ));
  1320.             CTFPlayer *pHealer = dynamic_cast<CTFPlayer *>(ClientEntityList().GetEnt( iHealerID ));
  1321.             if ( !pHealer->IsLocalPlayer() )
  1322.                 return;
  1323.  
  1324.             if ( pPatient )
  1325.                 UpdateRecentPatientHealthbar( pPatient );
  1326.             else
  1327.                 DevWarning( "patient_healed_notify called on client, but could not cast to player! userid : %i\n", iUserID );
  1328.             //DevMsg( "patient_healed_notify called on client! Woohoo! Name: %s, userid: %i, player\n" );
  1329.         }
  1330.     }
  1331. }
  1332. #endif // TF2C_BETA
  1333. #endif
  1334.  
Advertisement
Add Comment
Please, Sign In to add comment