diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/tf_weapon_shotgun.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/tf/tf_weapon_shotgun.cpp')
| -rw-r--r-- | game/shared/tf/tf_weapon_shotgun.cpp | 581 |
1 files changed, 581 insertions, 0 deletions
diff --git a/game/shared/tf/tf_weapon_shotgun.cpp b/game/shared/tf/tf_weapon_shotgun.cpp new file mode 100644 index 0000000..f233de1 --- /dev/null +++ b/game/shared/tf/tf_weapon_shotgun.cpp @@ -0,0 +1,581 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "tf_weapon_shotgun.h" +#include "decals.h" +#include "tf_fx_shared.h" +#include "takedamageinfo.h" +#include "tf_gamerules.h" + +// Client specific. +#if defined( CLIENT_DLL ) +#include "c_tf_player.h" +// Server specific. +#else +#include "tf_player.h" +#include "ilagcompensationmanager.h" +#include "collisionutils.h" +#include "in_buttons.h" +#endif + +//============================================================================= +// +// Weapon Shotgun tables. +// + +CREATE_SIMPLE_WEAPON_TABLE( TFShotgun, tf_weapon_shotgun_primary ) +CREATE_SIMPLE_WEAPON_TABLE( TFShotgun_Soldier, tf_weapon_shotgun_soldier ) +CREATE_SIMPLE_WEAPON_TABLE( TFShotgun_HWG, tf_weapon_shotgun_hwg ) +CREATE_SIMPLE_WEAPON_TABLE( TFShotgun_Pyro, tf_weapon_shotgun_pyro ) +CREATE_SIMPLE_WEAPON_TABLE( TFScatterGun, tf_weapon_scattergun ) +CREATE_SIMPLE_WEAPON_TABLE( TFShotgun_Revenge, tf_weapon_sentry_revenge ) +CREATE_SIMPLE_WEAPON_TABLE( TFSodaPopper, tf_weapon_soda_popper ) +CREATE_SIMPLE_WEAPON_TABLE( TFPEPBrawlerBlaster, tf_weapon_pep_brawler_blaster ) +CREATE_SIMPLE_WEAPON_TABLE( TFShotgunBuildingRescue, tf_weapon_shotgun_building_rescue ) + +#define SCATTERGUN_KNOCKBACK_MIN_DMG 30.0f +#define SCATTERGUN_KNOCKBACK_MIN_RANGE_SQ 160000.0f //400x400 +//============================================================================= +// +// Weapon Shotgun functions. +// +bool CanScatterGunKnockBack( CTFWeaponBase *pWeapon, float flDamage, float flDistanceSq ) +{ + int nBulletKnockBack = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pWeapon, nBulletKnockBack, set_scattergun_has_knockback ); + if ( nBulletKnockBack != 0 ) + { + if (flDamage > SCATTERGUN_KNOCKBACK_MIN_DMG && flDistanceSq < SCATTERGUN_KNOCKBACK_MIN_RANGE_SQ ) + return true; + + float flKnockbackMult = 1.0f; + CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pWeapon, flKnockbackMult, scattergun_knockback_mult ); + if ( flKnockbackMult > 1.0f ) + return true; + } + + return false; +} +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFShotgun::CTFShotgun() +{ + m_bReloadsSingly = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFShotgun::PrimaryAttack() +{ + if ( !CanAttack() ) + return; + + // Set the weapon mode. + m_iWeaponMode = TF_WEAPON_PRIMARY_MODE; + + BaseClass::PrimaryAttack(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFShotgun::UpdatePunchAngles( CTFPlayer *pPlayer ) +{ + // Update the player's punch angle. + QAngle angle = pPlayer->GetPunchAngle(); + float flPunchAngle = m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_flPunchAngle; + angle.x -= SharedRandomInt( "ShotgunPunchAngle", ( flPunchAngle - 1 ), ( flPunchAngle + 1 ) ); + pPlayer->SetPunchAngle( angle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFShotgun::PlayWeaponShootSound( void ) +{ + BaseClass::PlayWeaponShootSound(); + + if ( TFGameRules()->GameModeUsesUpgrades() ) + { + PlayUpgradedShootSound( "Weapon_Upgrade.DamageBonus" ); + } +} + +//----------------------------------------------------------------------------- +// CTFShotgun_Revenge +//----------------------------------------------------------------------------- +CTFShotgun_Revenge::CTFShotgun_Revenge() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFShotgun_Revenge::Precache() +{ + int iModelIndex = PrecacheModel( TF_WEAPON_TAUNT_FRONTIER_JUSTICE_GUITAR_MODEL ); + PrecacheGibsForModel( iModelIndex ); + PrecacheParticleSystem( "blood_impact_backscatter" ); + + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFShotgun_Revenge::PrimaryAttack() +{ + if ( !CanAttack() ) + return; + + BaseClass::PrimaryAttack(); + + // Do this after the attack, so that we know if we are doing custom damage + CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); + if ( pOwner ) + { + int iRevengeCrits = pOwner->m_Shared.GetRevengeCrits(); + pOwner->m_Shared.SetRevengeCrits( iRevengeCrits-1 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFShotgun_Revenge::SentryKilled( int iCrits ) +{ + int val = 0; + CALL_ATTRIB_HOOK_INT( val, sentry_killed_revenge ); + if ( val == 1 ) + { + CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); + if ( pOwner ) + { + pOwner->m_Shared.SetRevengeCrits( pOwner->m_Shared.GetRevengeCrits() + iCrits ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFShotgun_Revenge::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ +#ifdef GAME_DLL + CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); + if ( pOwner && pOwner->m_Shared.GetRevengeCrits() ) + { + pOwner->m_Shared.RemoveCond( TF_COND_CRITBOOSTED ); + } +#endif + + return BaseClass::Holster( pSwitchingTo ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFShotgun_Revenge::Deploy( void ) +{ +#ifdef GAME_DLL + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + if ( pOwner && pOwner->m_Shared.GetRevengeCrits() ) + { + pOwner->m_Shared.AddCond( TF_COND_CRITBOOSTED ); + } +#endif + + return BaseClass::Deploy(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFShotgun_Revenge::GetCustomDamageType() const +{ + CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); + if ( pOwner ) + { + int iRevengeCrits = pOwner->m_Shared.GetRevengeCrits(); + return iRevengeCrits > 0 ? TF_DMG_CUSTOM_SHOTGUN_REVENGE_CRIT : TF_DMG_CUSTOM_NONE; + } + return TF_DMG_CUSTOM_NONE; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFShotgun_Revenge::GetCount( void ) +{ + CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); + if ( pOwner ) + { + return pOwner->m_Shared.GetRevengeCrits(); + } + + return 0; +} + +#ifdef CLIENT_DLL + +//----------------------------------------------------------------------------- +// Purpose: +// ---------------------------------------------------------------------------- +void CTFShotgun_Revenge::SetWeaponVisible( bool visible ) +{ + if ( !visible ) + { + CTFPlayer *pPlayer = ToTFPlayer( GetOwner() ); + if ( pPlayer && pPlayer->m_Shared.InCond( TF_COND_TAUNTING ) && pPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_ENGINEER && pPlayer->m_Shared.GetTauntIndex() == TAUNT_BASE_WEAPON ) + { + int nModelIndex = modelinfo->GetModelIndex( TF_WEAPON_TAUNT_FRONTIER_JUSTICE_GUITAR_MODEL ); + CUtlVector<breakmodel_t> guitarGibs; + BuildGibList( guitarGibs, nModelIndex, 1.0f, COLLISION_GROUP_NONE ); + if ( guitarGibs.Count() > 0 ) + { + Vector vForward, vRight, vUp; + AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); + + Vector vecBreakVelocity = Vector(0,0,200); + AngularImpulse angularImpulse( RandomFloat( 0.0f, 120.0f ), RandomFloat( 0.0f, 120.0f ), 0.0 ); + Vector vecOrigin = GetAbsOrigin() + vForward*70 + vUp*10; + QAngle vecAngle = GetAbsAngles(); + breakablepropparams_t breakParams( vecOrigin, vecAngle, vecBreakVelocity, angularImpulse ); + breakParams.impactEnergyScale = 1.0f; + + CreateGibsFromList( guitarGibs, nModelIndex, NULL, breakParams, NULL, -1 , false, true ); + } + } + } + + BaseClass::SetWeaponVisible( visible ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// ---------------------------------------------------------------------------- +int CTFShotgun_Revenge::GetWorldModelIndex( void ) +{ + // Engineer guitar support. + CTFPlayer *pPlayer = ToTFPlayer( GetOwner() ); + if ( pPlayer && pPlayer->GetPlayerClass() && ( pPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_ENGINEER ) && + ( pPlayer->m_Shared.InCond( TF_COND_TAUNTING ) ) && ( pPlayer->m_Shared.GetTauntIndex() == TAUNT_BASE_WEAPON ) ) + { + // While we are taunting, replace our normal world model with the guitar. + m_iWorldModelIndex = modelinfo->GetModelIndex( TF_WEAPON_TAUNT_FRONTIER_JUSTICE_GUITAR_MODEL ); + return m_iWorldModelIndex; + } + + return BaseClass::GetWorldModelIndex(); +} +#endif + +#ifdef GAME_DLL +//----------------------------------------------------------------------------- +// Purpose: Reset revenge crits when the shotgun is changed +//----------------------------------------------------------------------------- +void CTFShotgun_Revenge::Detach( void ) +{ + CTFPlayer *pPlayer = GetTFPlayerOwner(); + if ( pPlayer ) + { + pPlayer->m_Shared.SetRevengeCrits( 0 ); + pPlayer->m_Shared.RemoveCond( TF_COND_CRITBOOSTED ); + } + + BaseClass::Detach(); +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFScatterGun::Reload( void ) +{ + int iWeaponMod = 0; + CALL_ATTRIB_HOOK_INT( iWeaponMod, set_scattergun_no_reload_single ); + if ( iWeaponMod == 1 ) + { + m_bReloadsSingly = false; + } + + return BaseClass::Reload(); +} + +#define JUMP_SPEED 268.3281572999747f +extern ConVar tf_player_movement_stun_time; +extern float AirBurstDamageForce( const Vector &size, float damage, float scale ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFScatterGun::FireBullet( CTFPlayer *pPlayer ) +{ +#ifndef CLIENT_DLL + if ( HasKnockback() ) + { + // Perform some knock back. + CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); + if ( !pOwner ) + return; + + // No knockback during pre-round freeze. + if ( TFGameRules() && (TFGameRules()->State_Get() == GR_STATE_PREROUND) ) + return; + + // Knock the firer back! + if ( !(pOwner->GetFlags() & FL_ONGROUND) && !pPlayer->m_bScattergunJump ) + { + pPlayer->m_bScattergunJump = true; + + pOwner->m_Shared.StunPlayer( 0.3f, 1.f, TF_STUN_MOVEMENT | TF_STUN_MOVEMENT_FORWARD_ONLY ); + + float flForce = AirBurstDamageForce( pOwner->WorldAlignSize(), 60, 6.f ); + + Vector vecForward; + AngleVectors( pOwner->EyeAngles(), &vecForward ); + Vector vecForce = vecForward * -flForce; + + EntityMatrix mtxPlayer; + mtxPlayer.InitFromEntity( pOwner ); + Vector vecAbsVelocity = pOwner->GetAbsVelocity(); + Vector vecAbsVelocityAsPoint = vecAbsVelocity + pOwner->GetAbsOrigin(); + Vector vecLocalVelocity = mtxPlayer.WorldToLocal( vecAbsVelocityAsPoint ); + + vecLocalVelocity.x = -300; + + vecAbsVelocityAsPoint = mtxPlayer.LocalToWorld( vecLocalVelocity ); + vecAbsVelocity = vecAbsVelocityAsPoint - pOwner->GetAbsOrigin(); + pOwner->SetAbsVelocity( vecAbsVelocity ); + + // Impulse an additional bit of Z push. + pOwner->ApplyAbsVelocityImpulse( Vector(0,0,50.f) ); + + // Slow player movement for a brief period of time. + pOwner->RemoveFlag( FL_ONGROUND ); + } + } +#endif + + BaseClass::FireBullet( pPlayer ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFScatterGun::ApplyPostHitEffects( const CTakeDamageInfo &inputInfo, CTFPlayer *pPlayer ) +{ +#ifndef CLIENT_DLL + if ( !HasKnockback() ) + return; + + CTFPlayer *pAttacker = ToTFPlayer( inputInfo.GetAttacker() ); + if ( !pAttacker ) + return; + + CTFPlayer *pTarget = pPlayer; + if ( !pTarget ) + return; + + if ( pTarget->m_Shared.GetWeaponKnockbackID() > -1 ) + return; + + float flDam = inputInfo.GetDamage(); + Vector vecDir = pAttacker->WorldSpaceCenter() - pTarget->WorldSpaceCenter(); + if ( !CanScatterGunKnockBack( this, flDam, vecDir.LengthSqr() ) ) + return; + + // Immune to pushback/knockback + if ( pTarget->m_Shared.InCond( TF_COND_MEGAHEAL ) ) + return; + + VectorNormalize( vecDir ); + + float flKnockbackMult = 3.0f; + CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( this, flKnockbackMult, scattergun_knockback_mult ); + + float flForce = AirBurstDamageForce( pTarget->WorldAlignSize(), flDam, flKnockbackMult ); + Vector vecForce = vecDir * -flForce; + vecForce.z += JUMP_SPEED; + + pTarget->ApplyAirBlastImpulse( vecForce ); + + pTarget->m_Shared.StunPlayer( 0.3f, 1.f, TF_STUN_MOVEMENT | TF_STUN_MOVEMENT_FORWARD_ONLY, pAttacker ); + pTarget->m_Shared.SetWeaponKnockbackID( pAttacker->GetUserID() ); + +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFScatterGun::FinishReload( void ) +{ + CTFPlayer* pOwner = ToTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + if ( UsesClipsForAmmo1() && !m_bReloadsSingly ) + { + int primary = MIN( GetMaxClip1() - m_iClip1, pOwner->GetAmmoCount(m_iPrimaryAmmoType)); + m_iClip1 += primary; + + // Takes a whole clip worth of ammo to reload, causing us to lose whatever was chambered. + pOwner->RemoveAmmo( GetMaxClip1(), m_iPrimaryAmmoType); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFScatterGun::HasKnockback( void ) +{ + int iWeaponMod = 0; + CALL_ATTRIB_HOOK_INT( iWeaponMod, set_scattergun_has_knockback ); + if ( iWeaponMod == 1 ) + return true; + else + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Play animation appropriate to ball status. +//----------------------------------------------------------------------------- +bool CTFScatterGun::SendWeaponAnim( int iActivity ) +{ + CTFPlayer *pPlayer = GetTFPlayerOwner(); + if ( !pPlayer ) + return BaseClass::SendWeaponAnim( iActivity ); + + if ( HasKnockback() ) + { + // Knockback version uses a different model and animation set. + switch ( iActivity ) + { + case ACT_VM_DRAW: + iActivity = ACT_ITEM2_VM_DRAW; + break; + case ACT_VM_HOLSTER: + iActivity = ACT_ITEM2_VM_HOLSTER; + break; + case ACT_VM_IDLE: + iActivity = ACT_ITEM2_VM_IDLE; + break; + case ACT_VM_PULLBACK: + iActivity = ACT_ITEM2_VM_PULLBACK; + break; + case ACT_VM_PRIMARYATTACK: + iActivity = ACT_ITEM2_VM_PRIMARYATTACK; + break; + case ACT_VM_SECONDARYATTACK: + iActivity = ACT_ITEM2_VM_SECONDARYATTACK; + break; + case ACT_VM_RELOAD: + iActivity = ACT_ITEM2_VM_RELOAD; + break; + case ACT_VM_DRYFIRE: + iActivity = ACT_ITEM2_VM_DRYFIRE; + break; + case ACT_VM_IDLE_TO_LOWERED: + iActivity = ACT_ITEM2_VM_IDLE_TO_LOWERED; + break; + case ACT_VM_IDLE_LOWERED: + iActivity = ACT_ITEM2_VM_IDLE_LOWERED; + break; + case ACT_VM_LOWERED_TO_IDLE: + iActivity = ACT_ITEM2_VM_LOWERED_TO_IDLE; + break; + default: + break; + } + } + + return BaseClass::SendWeaponAnim( iActivity ); +} + +#ifdef GAME_DLL +//----------------------------------------------------------------------------- +void CTFScatterGun::Equip( CBaseCombatCharacter *pOwner ) +{ + CTFPlayer *pPlayer = dynamic_cast<CTFPlayer*>( pOwner ); + if ( pPlayer ) + { + pPlayer->m_Shared.SetScoutHypeMeter( 0.0f ); + } + + BaseClass::Equip( pOwner ); +} +#endif // GAME_DLL +//----------------------------------------------------------------------------- +// CTFSodaPopper +//----------------------------------------------------------------------------- +float CTFSodaPopper::GetProgress( void ) +{ + CTFPlayer *pPlayer = GetTFPlayerOwner(); + if ( !pPlayer ) + return 0.f; + + return pPlayer->m_Shared.GetScoutHypeMeter() * 0.01f; +} + +//----------------------------------------------------------------------------- +void CTFSodaPopper::ItemBusyFrame( void ) +{ +#ifdef GAME_DLL + CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); + if ( pOwner && pOwner->m_nButtons & IN_ATTACK2 ) + { + // Check here so we can always activate buff when we want (similar to stickies) + SecondaryAttack(); + } +#endif + + BaseClass::ItemBusyFrame(); +} + +//----------------------------------------------------------------------------- +void CTFSodaPopper::SecondaryAttack() +{ + CTFPlayer *pPlayer = GetTFPlayerOwner( ); + if ( !pPlayer || pPlayer->m_Shared.IsHypeBuffed() ) + return; + + if ( pPlayer->m_Shared.GetScoutHypeMeter() >= 100.f ) + { + pPlayer->m_Shared.AddCond( TF_COND_SODAPOPPER_HYPE ); + } +} + +//----------------------------------------------------------------------------- +float CTFPEPBrawlerBlaster::GetProgress( void ) +{ + CTFPlayer *pPlayer = GetTFPlayerOwner(); + if ( !pPlayer ) + return 0.f; + + return pPlayer->m_Shared.GetScoutHypeMeter() * 0.01f; +} + +//----------------------------------------------------------------------------- +float CTFShotgunBuildingRescue::GetProjectileSpeed( void ) +{ + return RemapValClamped( 0.75f, 0.0f, 1.f, 1800, 2600 ); // Temp, if we want to ramp. +} + +//----------------------------------------------------------------------------- +float CTFShotgunBuildingRescue::GetProjectileGravity( void ) +{ + return RemapValClamped( 0.75f, 0.0f, 1.f, 0.5f, 0.1f ); // Temp, if we want to ramp. +} + +//----------------------------------------------------------------------------- +bool CTFShotgunBuildingRescue::IsViewModelFlipped( void ) +{ + return !BaseClass::IsViewModelFlipped(); // Invert because arrows are backwards by default. +}
\ No newline at end of file |