Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

312 lines
8.6 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
#include "cbase.h"
#include "tf_projectile_rocket.h"
#include "tf_projectile_arrow.h"
#include "tf_weapon_grenade_pipebomb.h"
class CTFPointWeaponMimic : public CPointEntity
{
DECLARE_CLASS( CTFPointWeaponMimic, CPointEntity );
public:
DECLARE_DATADESC();
CTFPointWeaponMimic();
~CTFPointWeaponMimic();
virtual void Spawn();
void InputFireOnce( inputdata_t& inputdata );
void InputFireMultiple( inputdata_t& inputdata );
void DetonateStickies( inputdata_t& inputdata );
private:
void Fire();
void FireRocket();
void FireGrenade();
void FireArrow();
void FireStickyGrenade();
enum eWeaponType
{
WEAPON_STANDARD_ROCKET,
WEAPON_STANDARD_GRENADE,
WEAPON_STANDARD_ARROW,
WEAPON_STICKY_GRENADE,
WEAPON_TYPES
};
QAngle GetFiringAngles() const;
float GetSpeed() const;
int m_nWeaponType;
bool m_bContinousFire;
// Effects for firing
const char* m_pzsFireSound;
const char* m_pzsFireParticles;
// Override/defaults for the projectile/bullets
const char* m_pzsModelOverride;
float m_flModelScale;
float m_flSpeedMin;
float m_flSpeedMax;
float m_flDamage;
float m_flSplashRadius;
float m_flSpreadAngle;
bool m_bCrits;
// List of active pipebombs
typedef CHandle<CTFGrenadePipebombProjectile> PipebombHandle;
CUtlVector<PipebombHandle> m_Pipebombs;
};
LINK_ENTITY_TO_CLASS( tf_point_weapon_mimic, CTFPointWeaponMimic );
// Data Description
BEGIN_DATADESC( CTFPointWeaponMimic )
// Keyfields
DEFINE_KEYFIELD( m_nWeaponType, FIELD_INTEGER, "WeaponType" ),
DEFINE_KEYFIELD( m_pzsFireSound, FIELD_SOUNDNAME, "FireSound" ),
DEFINE_KEYFIELD( m_pzsFireParticles, FIELD_STRING, "ParticleEffect" ),
DEFINE_KEYFIELD( m_pzsModelOverride, FIELD_MODELNAME, "ModelOverride" ),
DEFINE_KEYFIELD( m_flModelScale, FIELD_FLOAT, "ModelScale" ),
DEFINE_KEYFIELD( m_flSpeedMin, FIELD_FLOAT, "SpeedMin" ),
DEFINE_KEYFIELD( m_flSpeedMax, FIELD_FLOAT, "SpeedMax" ),
DEFINE_KEYFIELD( m_flDamage, FIELD_FLOAT, "Damage" ),
DEFINE_KEYFIELD( m_flSplashRadius, FIELD_FLOAT, "SplashRadius" ),
DEFINE_KEYFIELD( m_flSpreadAngle, FIELD_FLOAT, "SpreadAngle" ),
DEFINE_KEYFIELD( m_bCrits, FIELD_BOOLEAN, "Crits" ),
DEFINE_INPUTFUNC( FIELD_VOID, "FireOnce", InputFireOnce ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "FireMultiple", InputFireMultiple ),
DEFINE_INPUTFUNC( FIELD_VOID, "DetonateStickies", DetonateStickies ),
END_DATADESC()
CTFPointWeaponMimic::CTFPointWeaponMimic()
: m_pzsModelOverride( NULL )
{
}
CTFPointWeaponMimic::~CTFPointWeaponMimic()
{
}
void CTFPointWeaponMimic::Spawn()
{
BaseClass::Spawn();
if( m_pzsModelOverride )
{
PrecacheModel( m_pzsModelOverride );
}
ChangeTeam( TF_TEAM_BLUE );
}
void CTFPointWeaponMimic::InputFireOnce( inputdata_t& inputdata )
{
Fire();
}
void CTFPointWeaponMimic::InputFireMultiple( inputdata_t& inputdata )
{
int nNumFires = Max( 1, abs(inputdata.value.Int()) );
while( nNumFires-- )
{
Fire();
}
}
void CTFPointWeaponMimic::DetonateStickies( inputdata_t& inputdata )
{
int count = m_Pipebombs.Count();
for ( int i = 0; i < count; i++ )
{
CTFGrenadePipebombProjectile *pTemp = m_Pipebombs[i];
if ( pTemp )
{
//This guy will die soon enough.
if ( pTemp->IsEffectActive( EF_NODRAW ) )
continue;
pTemp->Detonate();
}
}
m_Pipebombs.Purge();
}
void CTFPointWeaponMimic::Fire()
{
Assert( m_nWeaponType >= 0 && m_nWeaponType < WEAPON_TYPES );
switch( m_nWeaponType )
{
case WEAPON_STANDARD_ROCKET:
FireRocket();
break;
case WEAPON_STANDARD_GRENADE:
FireGrenade();
break;
case WEAPON_STANDARD_ARROW:
FireArrow();
break;
case WEAPON_STICKY_GRENADE:
FireStickyGrenade();
break;
}
}
void CTFPointWeaponMimic::FireRocket()
{
CTFProjectile_Rocket *pProjectile = CTFProjectile_Rocket::Create( this, GetAbsOrigin(), GetFiringAngles(), this, NULL);
if ( pProjectile )
{
if( m_pzsModelOverride )
{
pProjectile->SetModel( m_pzsModelOverride );
}
pProjectile->ChangeTeam( TF_TEAM_BLUE );
pProjectile->SetCritical( m_bCrits );
pProjectile->SetDamage( m_flDamage );
Vector vVelocity = pProjectile->GetAbsVelocity().Normalized() * GetSpeed();
pProjectile->SetAbsVelocity( vVelocity );
pProjectile->SetupInitialTransmittedGrenadeVelocity( vVelocity );
pProjectile->SetCollisionGroup( TFCOLLISION_GROUP_ROCKET_BUT_NOT_WITH_OTHER_ROCKETS );
}
}
void CTFPointWeaponMimic::FireGrenade()
{
QAngle vFireAngles = GetFiringAngles();
Vector vForward, vUp;
AngleVectors( vFireAngles, &vForward, NULL, &vUp );
Vector vVelocity( vForward * GetSpeed() );
CTFGrenadePipebombProjectile *pGrenade = static_cast<CTFGrenadePipebombProjectile*>( CBaseEntity::CreateNoSpawn( "tf_projectile_pipe", GetAbsOrigin(), vFireAngles, this ) );
if ( pGrenade )
{
DispatchSpawn( pGrenade );
if( m_pzsModelOverride )
{
pGrenade->SetModel( m_pzsModelOverride );
}
pGrenade->InitGrenade( vVelocity, AngularImpulse( 600, random->RandomInt( -1200, 1200 ), 0 ), NULL, m_flDamage, m_flSplashRadius );
pGrenade->ChangeTeam( TF_TEAM_BLUE );
pGrenade->m_nSkin = 1;
pGrenade->SetDetonateTimerLength( 2.f );
pGrenade->SetModelScale( m_flModelScale );
pGrenade->SetCollisionGroup( TFCOLLISION_GROUP_ROCKETS ); // we want to use collision_group_rockets so we don't ever collide with players
pGrenade->SetDamage( m_flDamage );
pGrenade->SetFullDamage( m_flDamage );
pGrenade->SetDamageRadius( m_flSplashRadius );
pGrenade->SetCritical( m_bCrits );
vVelocity = pGrenade->GetAbsVelocity().Normalized() * GetSpeed();
pGrenade->SetAbsVelocity( vVelocity );
pGrenade->SetupInitialTransmittedGrenadeVelocity( vVelocity );
}
}
void CTFPointWeaponMimic::FireArrow()
{
CTFProjectile_Arrow *pProjectile = CTFProjectile_Arrow::Create( GetAbsOrigin(), GetFiringAngles(), 2000, 0.7f, TF_PROJECTILE_ARROW, this, NULL );
if ( pProjectile )
{
if( m_pzsModelOverride )
{
pProjectile->SetModel( m_pzsModelOverride );
}
pProjectile->ChangeTeam( TF_TEAM_BLUE );
pProjectile->SetCritical( m_bCrits );
pProjectile->SetDamage( m_flDamage );
Vector vVelocity = pProjectile->GetAbsVelocity().Normalized() * GetSpeed();
pProjectile->SetAbsVelocity( vVelocity );
pProjectile->SetupInitialTransmittedGrenadeVelocity( vVelocity );
pProjectile->SetCollisionGroup( TFCOLLISION_GROUP_ROCKET_BUT_NOT_WITH_OTHER_ROCKETS );
}
}
void CTFPointWeaponMimic::FireStickyGrenade()
{
QAngle vFireAngles = GetFiringAngles();
Vector vForward, vUp;
AngleVectors( vFireAngles, &vForward, NULL, &vUp );
Vector vVelocity( vForward * GetSpeed() );
CTFGrenadePipebombProjectile *pGrenade = static_cast<CTFGrenadePipebombProjectile*>( CBaseEntity::CreateNoSpawn( "tf_projectile_pipe", GetAbsOrigin(), vFireAngles, this ) );
if ( pGrenade )
{
pGrenade->m_bDefensiveBomb = true;
pGrenade->SetPipebombMode( TF_GL_MODE_REMOTE_DETONATE );
pGrenade->SetModelScale( m_flModelScale );
pGrenade->SetCollisionGroup( TFCOLLISION_GROUP_ROCKETS ); // we want to use collision_group_rockets so we don't ever collide with players
pGrenade->SetCanTakeDamage( false );
DispatchSpawn( pGrenade );
if( m_pzsModelOverride )
{
pGrenade->SetModel( m_pzsModelOverride );
}
else
{
pGrenade->SetModel( "models/weapons/w_models/w_stickybomb_d.mdl" );
}
pGrenade->InitGrenade( vVelocity, AngularImpulse( 600, random->RandomInt( -1200, 1200 ), 0 ), NULL, m_flDamage, m_flSplashRadius );
vVelocity = pGrenade->GetAbsVelocity().Normalized() * GetSpeed();
pGrenade->SetAbsVelocity( vVelocity );
pGrenade->SetupInitialTransmittedGrenadeVelocity( vVelocity );
pGrenade->SetDamage( m_flDamage );
pGrenade->SetFullDamage( m_flDamage );
pGrenade->SetDamageRadius( m_flSplashRadius );
pGrenade->SetCritical( m_bCrits );
pGrenade->ChangeTeam( TF_TEAM_BLUE );
pGrenade->m_nSkin = 1;
m_Pipebombs.AddToTail( pGrenade );
}
}
QAngle CTFPointWeaponMimic::GetFiringAngles() const
{
// No spread? Straight along our angles, then
QAngle angles = GetAbsAngles();
if( m_flSpreadAngle == 0 )
return angles;
Vector vForward, vRight, vUp;
AngleVectors( angles, &vForward, &vRight, &vUp );
// Rotate around up by half the spread input, then rotate around the original forward by +-180
float flHalfSpread = m_flSpreadAngle / 2.f;
VMatrix mtxRotateAroundUp = SetupMatrixAxisRot( vUp, RandomFloat( -flHalfSpread, flHalfSpread ) );
VMatrix mtxRotateAroundForward = SetupMatrixAxisRot( vForward, RandomFloat( -180, 180 ) );
// Rotate forward
VMatrix mtxSpreadRot;
MatrixMultiply( mtxRotateAroundForward, mtxRotateAroundUp, mtxSpreadRot );
vForward = mtxSpreadRot * vForward;
// Back to angles
VectorAngles( vForward, vUp, angles );
return angles;
}
float CTFPointWeaponMimic::GetSpeed() const
{
return RandomFloat( m_flSpeedMin, m_flSpeedMax );
}