mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user