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/tf2/weapon_flame_thrower.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/tf2/weapon_flame_thrower.cpp')
| -rw-r--r-- | game/shared/tf2/weapon_flame_thrower.cpp | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/game/shared/tf2/weapon_flame_thrower.cpp b/game/shared/tf2/weapon_flame_thrower.cpp new file mode 100644 index 0000000..9d98227 --- /dev/null +++ b/game/shared/tf2/weapon_flame_thrower.cpp @@ -0,0 +1,434 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "basetfplayer_shared.h" +#include "in_buttons.h" +#include "weapon_combatshield.h" +#include "weapon_flame_thrower.h" +#include "gasoline_shared.h" +#include "ammodef.h" + + +#define FLAME_THROWER_FIRE_INTERVAL 0.3 // Eject a fire blob entity this often. + +#define FLAMETHROWER_FLAME_DISTANCE 400.0 + +#define FLAMETHROWER_FLAME_SPEED 500.0 // + +#define FLAMETHROWER_DAMAGE_PER_SEC 1000 + +// How far the flame particles will spread from the center. +#define FLAMETHROWER_SPREAD_ANGLE 15.0 + + +// ------------------------------------------------------------------------------------------------ // +// Pretty little tables. +// ------------------------------------------------------------------------------------------------ // + +#if defined( CLIENT_DLL ) + + #include "vstdlib/random.h" + #include "engine/IEngineSound.h" + + #define FLAMETHROWER_PARTICLES_PER_SEC 100 + +#else + + #include "gasoline_blob.h" + #include "fire_damage_mgr.h" + #include "tf_gamerules.h" + + #define FLAMETHROWER_DAMAGE_INTERVAL 0.2 + +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +PRECACHE_WEAPON_REGISTER( weapon_flame_thrower ); + +LINK_ENTITY_TO_CLASS( weapon_flame_thrower, CWeaponFlameThrower ); + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponFlameThrower, DT_WeaponFlameThrower ) + +BEGIN_NETWORK_TABLE( CWeaponFlameThrower, DT_WeaponFlameThrower ) + #if defined( CLIENT_DLL ) + RecvPropInt( RECVINFO( m_bFiring ) ) + #else + SendPropInt( SENDINFO( m_bFiring ), 1, SPROP_UNSIGNED ) + #endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponFlameThrower ) + + DEFINE_PRED_FIELD( m_bFiring, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + +END_PREDICTION_DATA() + + +static inline void GenerateRandomFlameThrowerVelocity( Vector &vOut, const Vector &vForward, const Vector &vRight, const Vector &vUp ) +{ + static float radians = DEG2RAD( 90 - FLAMETHROWER_SPREAD_ANGLE ); + static float v = cos( radians ) / sin( radians ); + + vOut = vForward + vRight * RandomFloat( -v, v ) + vUp * RandomFloat( -v, v ); + VectorNormalize( vOut ); +} + +template< class T > +int FindInArray( const T pTest, const T *pArray, int arrayLen ) +{ + for ( int i=0; i < arrayLen; i++ ) + { + if ( pTest == pArray[i] ) + return i; + } + return -1; +} + + +// ------------------------------------------------------------------------------------------------ // +// CWeaponFlameThrower implementation. +// ------------------------------------------------------------------------------------------------ // + +CWeaponFlameThrower::CWeaponFlameThrower() +{ + InternalConstructor( false ); +} + + +CWeaponFlameThrower::CWeaponFlameThrower( bool bCanister ) +{ + InternalConstructor( bCanister ); +} + +void CWeaponFlameThrower::Precache() +{ + BaseClass::Precache(); + + PrecacheScriptSound( "FlameThrower.Sound" ); +} + +void CWeaponFlameThrower::InternalConstructor( bool bCanister ) +{ + m_bCanister = bCanister; + + m_bFiring = false; + m_flNextPrimaryAttack = -1; + + #if defined( CLIENT_DLL ) + { + m_hFlameEmitter = CSimpleEmitter::Create( "flamethrower" ); + + m_hFireMaterial = INVALID_MATERIAL_HANDLE; + if ( IsGasCanister() ) + { + m_hFireMaterial = m_hFlameEmitter->GetPMaterial( "particle/particle_noisesphere" ); + } + else + { + m_hFireMaterial = m_hFlameEmitter->GetPMaterial( "particle/fire" ); + } + + m_FlameEvent.Init( FLAMETHROWER_PARTICLES_PER_SEC ); + + m_bSoundOn = false; + } + #endif +} + + +CWeaponFlameThrower::~CWeaponFlameThrower() +{ + #if defined( CLIENT_DLL ) + StopFlameSound(); + #endif +} + + +bool CWeaponFlameThrower::IsGasCanister() const +{ + return m_bCanister; +} + + +bool CWeaponFlameThrower::IsPredicted() const +{ + return true; +} + + +void CWeaponFlameThrower::ItemPostFrame() +{ + CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + if ( pOwner->IsAlive() && + (pOwner->m_nButtons & IN_ATTACK) && + GetShieldState() == SS_DOWN && + GetPrimaryAmmo() > 2 ) + { + PrimaryAttack(); + m_bFiring = true; + + // Prevent shield post frame if we're not ready to attack, or we're healing + AllowShieldPostFrame( false ); + } + else + { + AllowShieldPostFrame( true ); + m_flNextPrimaryAttack = -1; + m_bFiring = false; + +#if defined( CLIENT_DLL ) +#else + m_hPrevBlob = NULL; + + // It's easy to lay down gasoline and forget to leave enough ammo to ignite it, so + // this allows the pyro to ignite any nearby gasoline blobs for free. + if ( !m_bCanister && GetPrimaryAmmo() <= 2 ) + { + IgniteNearbyGasolineBlobs(); + } +#endif + } +} + + +void CWeaponFlameThrower::PrimaryAttack() +{ + #if defined( CLIENT_DLL ) + + #else + + CBasePlayer *pOwner = ToBaseTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + // Ok.. find eligible entities in a cone in front of us. + Vector vOrigin = pOwner->Weapon_ShootPosition( ); + Vector vForward, vRight, vUp; + AngleVectors( pOwner->GetAbsAngles(), &vForward, &vRight, &vUp ); + + // Find some entities to burn. + CBaseEntity *pHitEnts[64]; + int nHitEnts = 0; + + #define NUM_TEST_VECTORS 30 + for ( int iTest=0; iTest < NUM_TEST_VECTORS; iTest++ ) + { + Vector vVel; + GenerateRandomFlameThrowerVelocity( vVel, vForward, vRight, vUp ); + + trace_t tr; + UTIL_TraceLine( vOrigin, vOrigin + vVel * FLAMETHROWER_FLAME_DISTANCE, MASK_SHOT & (~CONTENTS_HITBOX), NULL, COLLISION_GROUP_NONE, &tr ); + if ( tr.m_pEnt ) + { + if ( TFGameRules()->IsTraceBlockedByWorldOrShield( vOrigin, vOrigin + vVel * FLAMETHROWER_FLAME_DISTANCE, GetOwner(), DMG_BURN | DMG_PROBE, &tr ) == false ) + { + CBaseEntity *pTestEnt = tr.m_pEnt; + if ( pTestEnt && IsBurnableEnt( pTestEnt, GetTeamNumber() ) ) + { + if ( FindInArray( pTestEnt, pHitEnts, nHitEnts ) == -1 ) + { + pHitEnts[nHitEnts++] = pTestEnt; + if ( nHitEnts >= ARRAYSIZE( pHitEnts ) ) + break; + } + } + } + } + } + + for ( int iHitEnt=0; iHitEnt < nHitEnts; iHitEnt++ ) + { + CBaseEntity *pEnt = pHitEnts[iHitEnt]; + + float flDist = (pEnt->GetAbsOrigin() - vOrigin).Length(); + float flPercent = 1.0 - flDist / FLAMETHROWER_FLAME_DISTANCE; + if ( flPercent < 0.1 ) + flPercent = 0.1; + + float flDamage = flPercent * FLAMETHROWER_DAMAGE_PER_SEC; + GetFireDamageMgr()->AddDamage( pEnt, GetOwner(), flDamage, !IsGasolineBlob( pEnt ) ); + } + + + // Drop a new petrol blob. + if ( gpGlobals->curtime >= m_flNextPrimaryAttack ) + { + float flLifetime = MAX_LIT_GASOLINE_BLOB_LIFETIME; + if ( IsGasCanister() ) + flLifetime = MAX_UNLIT_GASOLINE_BLOB_LIFETIME; + + CGasolineBlob *pBlob = CGasolineBlob::Create( GetOwner(), vOrigin, vForward * FLAMETHROWER_FLAME_SPEED, false, FLAMETHROWER_FLAME_DISTANCE / FLAMETHROWER_FLAME_SPEED, flLifetime ); + if ( pBlob ) + { + if ( IsGasCanister() ) + { + // Link the previous blob to this one. + pBlob->AddAutoBurnBlob( m_hPrevBlob ); + if ( m_hPrevBlob.Get() ) + m_hPrevBlob->AddAutoBurnBlob( pBlob ); + + m_hPrevBlob = pBlob; + } + else + { + pBlob->SetLit( true ); + } + } + + pOwner->RemoveAmmo( 2, m_iPrimaryAmmoType ); + + // Drop a blob every half second. + m_flNextPrimaryAttack = gpGlobals->curtime + FLAME_THROWER_FIRE_INTERVAL; + } + + #endif +} + + +#if defined( CLIENT_DLL ) + + bool CWeaponFlameThrower::ShouldPredict() + { + if ( GetOwner() == C_BasePlayer::GetLocalPlayer() ) + return true; + + return BaseClass::ShouldPredict(); + } + + + void CWeaponFlameThrower::NotifyShouldTransmit( ShouldTransmitState_t state ) + { + BaseClass::NotifyShouldTransmit( state ); + + if ( state == SHOULDTRANSMIT_START ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + else if ( state == SHOULDTRANSMIT_END ) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + StopFlameSound(); + } + } + + void CWeaponFlameThrower::ClientThink() + { + // Spew some particles out. + if ( !IsDormant() && IsCarrierAlive() && m_bFiring && m_hFlameEmitter.IsValid() ) + { + unsigned char color[4] = { 255, 128, 0, 255 }; + if ( IsGasCanister() ) + { + color[0] = color[1] = color[2] = 200; + color[3] = 255; + } + + StartSound(); + + Vector vForward, vUp, vRight, vOrigin; + QAngle vAngles; + GetShootPosition( vOrigin, vAngles ); + AngleVectors( vAngles, &vForward, &vRight, &vUp ); + + // Spew out flame particles. + float dt = gpGlobals->frametime; + while ( m_FlameEvent.NextEvent( dt ) ) + { + SimpleParticle *p = m_hFlameEmitter->AddSimpleParticle( + m_hFireMaterial, + vOrigin + RandomVector( -3, 3 ), + FLAMETHROWER_FLAME_DISTANCE / FLAMETHROWER_FLAME_SPEED, // lifetime, + 9 // size + ); + + if ( p ) + { + p->m_uchColor[0] = color[0]; + p->m_uchColor[1] = color[1]; + p->m_uchColor[2] = color[2]; + p->m_uchStartAlpha = color[3]; + p->m_uchEndAlpha = 0; + GenerateRandomFlameThrowerVelocity( p->m_vecVelocity, vForward, vRight, vUp ); + p->m_vecVelocity *= RandomFloat( FLAMETHROWER_FLAME_SPEED * 0.9, FLAMETHROWER_FLAME_SPEED * 1.1 ); + } + } + } + else + { + StopFlameSound(); + } + } + + + void CWeaponFlameThrower::StartSound() + { + if ( !m_bSoundOn ) + { + CLocalPlayerFilter filter; + EmitSound( filter, entindex(), "FlameThrower.Sound" ); + + m_bSoundOn = true; + } + } + + + void CWeaponFlameThrower::StopFlameSound() + { + if ( m_bSoundOn ) + { + StopSound( entindex(), "FlameThrower.Sound" ); + m_bSoundOn = false; + } + } + + +#else + + bool CWeaponFlameThrower::Holster( CBaseCombatWeapon *pSwitchingTo ) + { + m_bFiring = false; + + return BaseClass::Holster( pSwitchingTo ); + } + + + void CWeaponFlameThrower::IgniteNearbyGasolineBlobs() + { + CBasePlayer *pOwner = ToBaseTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + Vector vOrigin = pOwner->Weapon_ShootPosition( ); + CBaseEntity *ents[128]; + float dists[128]; + int nEnts = FindBurnableEntsInSphere( + ents, + dists, + ARRAYSIZE( dists ), + vOrigin, + 50, + pOwner ); + + for ( int i=0; i < nEnts; i++ ) + { + CGasolineBlob *pBlob = dynamic_cast< CGasolineBlob* >( ents[i] ); + if ( pBlob ) + { + GetFireDamageMgr()->AddDamage( pBlob, pOwner, 500, false ); + } + } + } + +#endif + + |