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.

323 lines
9.7 KiB

5 years ago
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "in_buttons.h"
#include "tf_gamerules.h"
#include "weapon_combatshield.h"
#if defined( CLIENT_DLL )
#include "particles_simple.h"
#include "fx.h"
#include "fx_quad.h"
#include "clienteffectprecachesystem.h"
#define CWeaponArcWelder C_WeaponArcWelder
#else
#endif
#include "weapon_repairgun.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Buff ranges
ConVar weapon_arcwelder_target_range( "weapon_arcwelder_target_range", "90", FCVAR_REPLICATED, "The farthest away you can be for the arcwelder to initially lock onto a target." );
ConVar weapon_arcwelder_stick_range( "weapon_arcwelder_stick_range", "100", FCVAR_REPLICATED, "How far away the arcwelder can stay locked onto someone." );
ConVar weapon_arcwelder_rate( "weapon_arcwelder_rate", "15", FCVAR_REPLICATED );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CWeaponArcWelder : public CWeaponRepairGun
{
DECLARE_CLASS( CWeaponArcWelder, CWeaponRepairGun );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponArcWelder( void );
virtual void Precache();
virtual float GetTargetRange( void );
virtual float GetStickRange( void );
virtual float GetHealRate( void );
virtual bool AppliesModifier( void ) { return false; }
virtual bool TargetsPlayers( void ) { return false; }
virtual CBaseEntity *GetTargetToHeal( CBaseEntity *pCurHealing );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual void ClientThink( void );
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
virtual void ViewModelDrawn( C_BaseViewModel *pViewModel );
virtual bool ShouldPredict( void )
{
if ( GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
private:
bool m_bWelding;
#if defined( CLIENT_DLL )
float m_flNextEffectTime;
#endif
private:
CWeaponArcWelder( const CWeaponArcWelder & );
};
LINK_ENTITY_TO_CLASS( weapon_arcwelder, CWeaponArcWelder );
PRECACHE_WEAPON_REGISTER( weapon_arcwelder );
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponArcWelder, DT_WeaponArcWelder )
BEGIN_NETWORK_TABLE( CWeaponArcWelder, DT_WeaponArcWelder )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponArcWelder )
END_PREDICTION_DATA()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponArcWelder::CWeaponArcWelder()
{
SetPredictionEligible( true );
m_bWelding = false;
#ifdef CLIENT_DLL
m_flNextEffectTime = 0;
#endif
}
void CWeaponArcWelder::Precache()
{
BaseClass::Precache();
PrecacheScriptSound( "WeaponRepairGun.Healing" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponArcWelder::GetTargetRange( void )
{
return weapon_arcwelder_target_range.GetFloat();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponArcWelder::GetStickRange( void )
{
return weapon_arcwelder_target_range.GetFloat();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponArcWelder::GetHealRate( void )
{
return weapon_arcwelder_rate.GetFloat();
}
//-----------------------------------------------------------------------------
// Purpose: Returns a pointer to a healable target
//-----------------------------------------------------------------------------
CBaseEntity *CWeaponArcWelder::GetTargetToHeal( CBaseEntity *pCurHealing )
{
CBaseEntity *pTarget = BaseClass::GetTargetToHeal(pCurHealing);
if ( !pTarget )
return pTarget;
// Make sure the target is within our field of view
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return NULL;
Vector vecAiming;
pOwner->EyeVectors( &vecAiming );
// Find a player in range of this player, and make sure they're healable.
Vector vecSrc = pOwner->Weapon_ShootPosition( );
Vector vecEnd = vecSrc + vecAiming * GetTargetRange();
trace_t tr;
// Use WeaponTraceLine so shields are tested...
TFGameRules()->WeaponTraceLine( vecSrc, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), pOwner, DMG_PROBE, &tr );
if ( tr.fraction != 1.0 && tr.m_pEnt == pTarget )
return pTarget;
return NULL;
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponArcWelder::ClientThink( void )
{
CBasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer )
return;
if ( m_hHealingTarget == NULL )
return;
// Don't show it while the player is dead. Ideally, we'd respond to m_bHealing in OnDataChanged,
// but it stops sending the weapon when it's holstered, and it gets holstered when the player dies.
C_BasePlayer *pFiringPlayer = dynamic_cast< C_BasePlayer* >( GetOwner() );
if ( !pFiringPlayer || pFiringPlayer->IsPlayerDead() )
{
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_NEVER );
m_bPlayingSound = false;
StopRepairSound();
return;
}
// Start playing the heal sound, if we're not already
if ( !m_bPlayingSound )
{
m_bPlayingSound = true;
CLocalPlayerFilter filter;
EmitSound( filter, entindex(), "WeaponRepairGun.Healing" );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponArcWelder::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
{
CBaseTFPlayer *pPlayer = static_cast<CBaseTFPlayer*>( GetOwner() );
if ( !pPlayer )
return true;
switch ( event )
{
case 7001:
m_bWelding = true;
return true;
case 7002:
m_bWelding = false;
return true;
default:
break;
};
return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
}
CLIENTEFFECT_REGISTER_BEGIN( PrecacheArcWelderEffect )
CLIENTEFFECT_MATERIAL( "particle/smoke_arcwelder" )
CLIENTEFFECT_MATERIAL( "effects/spark2" )
CLIENTEFFECT_MATERIAL( "effects/blueflare" )
CLIENTEFFECT_MATERIAL( "effects/blueflare2" )
CLIENTEFFECT_REGISTER_END()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponArcWelder::ViewModelDrawn( C_BaseViewModel *pViewModel )
{
if ( !m_bWelding || !m_hHealingTarget.Get() )
return;
if ( m_flNextEffectTime > gpGlobals->curtime )
return;
m_flNextEffectTime = gpGlobals->curtime + 0.1;
// Get our weldpoint
Vector attachOrigin;
QAngle attachAngles;
pViewModel->GetAttachment( pViewModel->LookupAttachment("muzzle"), attachOrigin, attachAngles );
Vector vecEnd = m_hHealingTarget->WorldSpaceCenter();
trace_t tr;
// Use WeaponTraceLine so shields are tested...
TFGameRules()->WeaponTraceLine( attachOrigin, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), GetOwner(), DMG_PROBE, &tr );
// Smoke
unsigned char color[3];
int iColOff = random->RandomInt(-16,16);
color[0] = 120 + iColOff;
color[1] = 230 + iColOff;
color[2] = 235 + iColOff;
/*
// Pull out from the target a bit
Vector vecOrigin = vecEnd;
Vector vecFromTarget = (vecEnd - attachOrigin);
VectorNormalize( vecFromTarget );
vecOrigin -= (vecFromTarget * 24);
*/
Vector vecOrigin = attachOrigin;
// Velocity
Vector vecVelocity = tr.plane.normal;
vecVelocity.z += random->RandomFloat( 8, 12 );
// Add it
CSmartPtr<CSimpleEmitter> pSimple = FX_Smoke( vecOrigin, vecVelocity,
random->RandomFloat( 4, 8 ), // Scale
1,
random->RandomFloat( 0.5, 3.0 ), // Dietime
color,
random->RandomInt( 64, 200 ), // Alpha
"particle/smoke_arcwelder",
random->RandomInt(0,255), // Roll
0 ); // Rolldelta
// Sparks
FX_Sparks( vecOrigin, 1, 4, tr.plane.normal, 2.5, 8, 64, "effects/spark2" );
// Bright Glow
SimpleParticle *sParticle;
sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/blueflare" ), vecOrigin );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.5f;
sParticle->m_vecVelocity.Init();
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 255;
sParticle->m_uchColor[2] = 255;
sParticle->m_uchStartSize = random->RandomInt(5,7);
sParticle->m_uchEndSize = sParticle->m_uchStartSize;
sParticle->m_flRoll = random->RandomInt(0,360);
sParticle->m_flRollDelta = 0;
// Dull Glow
sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/blueflare2" ), vecOrigin );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.2f;
sParticle->m_vecVelocity.Init();
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 255;
sParticle->m_uchColor[2] = 255;
sParticle->m_uchStartSize = random->RandomInt(15,20);
sParticle->m_uchEndSize = sParticle->m_uchStartSize;
sParticle->m_flRoll = random->RandomInt(0,360);
sParticle->m_flRollDelta = 0;
}
#endif