2024-08-29 19:18:30 -04:00
# include "cbase.h"
# include "npcevent.h"
# include "Sprite.h"
# include "beam_shared.h"
# include "takedamageinfo.h"
# include "gamerules.h"
# include "in_buttons.h"
# include "soundenvelope.h"
# ifdef CLIENT_DLL
# include "c_baseplayer.h"
# include "c_asw_player.h"
# include "c_asw_marine.h"
# include "ivieweffects.h"
# include "c_te_effect_dispatch.h"
2024-08-29 19:33:14 -04:00
# include "prediction.h"
2024-08-29 19:18:30 -04:00
# include "fx.h"
# define CASW_Player C_ASW_Player
# define CASW_Marine C_ASW_Marine
# else
# include "asw_lag_compensation.h"
# include "player.h"
# include "asw_player.h"
# include "asw_marine.h"
# include "soundent.h"
# include "game.h"
# include "te_effect_dispatch.h"
# include "asw_marine_speech.h"
# include "asw_weapon_ammo_bag_shared.h"
# endif
# include "vstdlib/random.h"
# include "engine/IEngineSound.h"
# include "IEffects.h"
# include "asw_marine_skills.h"
# include "shake.h"
# include "asw_util_shared.h"
# include "asw_weapon_chainsaw_shared.h"
# include "asw_weapon_parse.h"
# define ASW_CHAINSAW_CHARGE_UP_TIME 1.0
# define ASW_CHAINSAW_PULSE_INTERVAL 0.1
# define ASW_CHAINSAW_DISCHARGE_INTERVAL 0.1
# define ASW_CHAINSAW_RANGE 30
# define ASW_CHAINSAW_BEAM_SPRITE "swarm / sprites / mlaserbeam.vmt"
# define ASW_CHAINSAW_FLARE_SPRITE "swarm / sprites / mlaserspark.vmt"
extern ConVar sk_plr_dmg_asw_cs ;
extern int g_sModelIndexSmoke ; // (in combatweapon.cpp) holds the index for the smoke cloud
IMPLEMENT_NETWORKCLASS_ALIASED ( ASW_Weapon_Chainsaw , DT_ASW_Weapon_Chainsaw ) ;
BEGIN_NETWORK_TABLE ( CASW_Weapon_Chainsaw , DT_ASW_Weapon_Chainsaw )
END_NETWORK_TABLE ( )
# if defined( CLIENT_DLL )
BEGIN_PREDICTION_DATA ( CASW_Weapon_Chainsaw )
DEFINE_FIELD ( m_fireState , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_flAmmoUseTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flShakeTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flStartFireTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flDmgTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flFireAnimTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flLastHitTime , FIELD_FLOAT ) ,
END_PREDICTION_DATA ( )
# endif
LINK_ENTITY_TO_CLASS ( asw_weapon_chainsaw , CASW_Weapon_Chainsaw ) ;
PRECACHE_WEAPON_REGISTER ( asw_weapon_chainsaw ) ;
# ifndef CLIENT_DLL
BEGIN_DATADESC ( CASW_Weapon_Chainsaw )
DEFINE_FIELD ( m_fireState , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_flAmmoUseTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flShakeTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flStartFireTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flDmgTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flFireAnimTime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_hBeam , FIELD_EHANDLE ) ,
DEFINE_FIELD ( m_hNoise , FIELD_EHANDLE ) ,
END_DATADESC ( )
# endif
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CASW_Weapon_Chainsaw : : CASW_Weapon_Chainsaw ( void )
{
m_flFireAnimTime = 0.0f ;
m_flTargetChainsawPitch = 0.0f ;
m_flDmgTime = 0.0f ;
m_bReloadsSingly = false ;
m_bFiresUnderwater = true ;
m_bPlayedIdleSound = false ;
m_pChainsawAttackSound = NULL ;
m_pChainsawAttackOffSound = NULL ;
# ifdef GAME_DLL
m_fLastForcedFireTime = 0 ; // last time we forced an AI marine to push its fire button
# endif
}
CASW_Weapon_Chainsaw : : ~ CASW_Weapon_Chainsaw ( )
{
if ( m_fireState ! = FIRE_OFF )
{
EndAttack ( ) ;
}
else
{
if ( m_bPlayedIdleSound )
{
StopSound ( " ASW_Chainsaw.Start " ) ;
if ( CBaseEntity : : IsAbsQueriesValid ( ) )
EmitSound ( " ASW_Chainsaw.Stop " ) ;
}
}
StopChainsawSound ( ) ;
StopAttackOffSound ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Weapon_Chainsaw : : Precache ( void )
{
PrecacheScriptSound ( " ASW_Chainsaw.Start " ) ;
PrecacheScriptSound ( " ASW_Chainsaw.Stop " ) ;
PrecacheScriptSound ( " ASW_Chainsaw.attackOn " ) ;
PrecacheScriptSound ( " ASW_Chainsaw.attackOff " ) ;
PrecacheModel ( ASW_CHAINSAW_BEAM_SPRITE ) ;
PrecacheModel ( ASW_CHAINSAW_FLARE_SPRITE ) ;
PrecacheParticleSystem ( " mining_laser_exhaust " ) ;
BaseClass : : Precache ( ) ;
}
bool CASW_Weapon_Chainsaw : : HasAmmo ( )
{
return true ;
//return m_iClip1 > 0;
}
bool CASW_Weapon_Chainsaw : : Deploy ( void )
{
SetFiringState ( FIRE_OFF ) ;
m_bPlayedIdleSound = true ;
EmitSound ( " ASW_Chainsaw.Start " ) ;
SetWeaponIdleTime ( gpGlobals - > curtime + 0.7f ) ;
return BaseClass : : Deploy ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CASW_Weapon_Chainsaw : : PrimaryAttack ( void )
{
// If my clip is empty (and I use clips) start reload
//if ( UsesClipsForAmmo1() && !m_iClip1 )
//{
//Reload();
//return;
//}
CASW_Player * pPlayer = GetCommander ( ) ;
CASW_Marine * pMarine = GetMarine ( ) ;
if ( ! pMarine | | ! pMarine - > IsAlive ( ) )
{
EndAttack ( ) ;
return ;
}
// don't fire underwater
if ( pMarine - > GetWaterLevel ( ) = = 3 )
{
if ( m_fireState ! = FIRE_OFF | | m_hBeam )
{
EndAttack ( ) ;
}
else
{
WeaponSound ( EMPTY ) ;
}
m_flNextPrimaryAttack = gpGlobals - > curtime + GetWeaponInfo ( ) - > m_flFireRate ;
m_flNextSecondaryAttack = gpGlobals - > curtime + GetWeaponInfo ( ) - > m_flFireRate ;
return ;
}
# ifdef GAME_DLL // check for turning on lag compensation
if ( pPlayer & & pMarine - > IsInhabited ( ) )
{
CASW_Lag_Compensation : : RequestLagCompensation ( pPlayer , pPlayer - > GetCurrentUserCommand ( ) ) ;
}
# endif
Vector vecSrc = pMarine - > Weapon_ShootPosition ( ) ;
Vector vecAiming = vec3_origin ;
if ( pPlayer & & pMarine - > IsInhabited ( ) )
{
vecAiming = pPlayer - > GetAutoaimVectorForMarine ( pMarine , GetAutoAimAmount ( ) , GetVerticalAdjustOnlyAutoAimAmount ( ) ) ; // 45 degrees = 0.707106781187
}
else
{
# ifndef CLIENT_DLL
vecAiming = pMarine - > GetActualShootTrajectory ( vecSrc ) ;
# endif
}
// make vecaiming go down at 45 degrees
vecAiming . z = 0 ;
VectorNormalize ( vecAiming ) ;
vecAiming . z = - 1.0f ;
VectorNormalize ( vecAiming ) ;
switch ( m_fireState )
{
case FIRE_OFF :
{
//if ( !HasAmmo() )
//{
//m_flNextPrimaryAttack = gpGlobals->curtime + 0.25;
//m_flNextSecondaryAttack = gpGlobals->curtime + 0.25;
//WeaponSound( EMPTY );
//return;
//}
m_flAmmoUseTime = gpGlobals - > curtime ; // start using ammo ASAP.
SendWeaponAnim ( ACT_VM_PRIMARYATTACK ) ;
m_flShakeTime = 0 ;
m_flStartFireTime = gpGlobals - > curtime ;
SetWeaponIdleTime ( gpGlobals - > curtime + 0.1 ) ;
m_flDmgTime = gpGlobals - > curtime + ASW_CHAINSAW_PULSE_INTERVAL ;
SetFiringState ( FIRE_STARTUP ) ;
}
break ;
case FIRE_STARTUP :
{
Fire ( vecSrc , vecAiming ) ;
# ifndef CLIENT_DLL
pMarine - > OnWeaponFired ( this , 1 ) ;
# endif
if ( gpGlobals - > curtime > = ( m_flStartFireTime + ASW_CHAINSAW_CHARGE_UP_TIME ) )
{
//EmitSound( "ASW_Chainsaw.AttackLoop" );
SetFiringState ( FIRE_CHARGE ) ;
}
if ( ! HasAmmo ( ) )
{
EndAttack ( ) ;
m_flNextPrimaryAttack = gpGlobals - > curtime + 1.0 ;
m_flNextSecondaryAttack = gpGlobals - > curtime + 1.0 ;
}
}
break ;
case FIRE_CHARGE :
{
Fire ( vecSrc , vecAiming ) ;
# ifndef CLIENT_DLL
pMarine - > OnWeaponFired ( this , 1 ) ;
# endif
if ( ! HasAmmo ( ) )
{
EndAttack ( ) ;
m_flNextPrimaryAttack = gpGlobals - > curtime + 1.0 ;
m_flNextSecondaryAttack = gpGlobals - > curtime + 1.0 ;
}
}
break ;
}
}
void CASW_Weapon_Chainsaw : : Fire ( const Vector & vecOrigSrc , const Vector & vecDir )
{
CASW_Marine * pMarine = GetMarine ( ) ;
if ( ! pMarine )
{
return ;
}
StopAttackOffSound ( ) ;
StartChainsawSound ( ) ;
if ( m_flFireAnimTime < gpGlobals - > curtime )
{
pMarine - > DoAnimationEvent ( PLAYERANIMEVENT_FIRE_GUN_PRIMARY ) ;
m_flFireAnimTime = gpGlobals - > curtime + 0.1f ;
}
Vector vecDest = vecOrigSrc + ( vecDir * ASW_CHAINSAW_RANGE ) ;
bool bDamageTime = m_flDmgTime < gpGlobals - > curtime ;
bool bHit = false ;
Ray_t ray ;
ray . Init ( vecOrigSrc , vecDest , Vector ( - 5 , - 5 , - 5 ) , Vector ( 5 , 5 , 25 ) ) ;
CBaseEntity * ( pEntities [ 8 ] ) ;
CHurtableEntitiesEnum hurtableEntities ( pEntities , 8 ) ;
partition - > EnumerateElementsAlongRay ( PARTITION_ENGINE_NON_STATIC_EDICTS | PARTITION_ENGINE_SOLID_EDICTS , ray , false , & hurtableEntities ) ;
trace_t tr ;
for ( int i = 0 ; i < hurtableEntities . GetCount ( ) ; + + i )
{
CBaseEntity * pEntity = pEntities [ i ] ;
if ( pEntity = = NULL | | pEntity = = pMarine )
continue ;
bHit = true ;
if ( bDamageTime )
{
// wide mode does damage to the ent, and radius damage
if ( pEntity - > m_takedamage ! = DAMAGE_NO )
{
CTraceFilterOnlyHitThis filter ( pEntity ) ;
UTIL_TraceHull ( vecOrigSrc , vecDest , Vector ( - 5 , - 5 , - 2 ) , Vector ( 5 , 5 , 25 ) , MASK_SHOT , & filter , & tr ) ;
ClearMultiDamage ( ) ;
float fDamage = 0.5f * GetWeaponInfo ( ) - > m_flBaseDamage + MarineSkills ( ) - > GetSkillBasedValueByMarine ( pMarine , ASW_MARINE_SKILL_MELEE , ASW_MARINE_SUBSKILL_MELEE_DMG ) ;
CTakeDamageInfo info ( this , pMarine , fDamage * g_pGameRules - > GetDamageMultiplier ( ) , DMG_SLASH ) ;
info . SetWeapon ( this ) ;
CalculateMeleeDamageForce ( & info , vecDir , tr . endpos ) ;
pEntity - > DispatchTraceAttack ( info , vecDir , & tr ) ;
ApplyMultiDamage ( ) ;
}
// radius damage a little more potent in multiplayer.
# ifndef CLIENT_DLL
//RadiusDamage( CTakeDamageInfo( this, pMarine, sk_plr_dmg_asw_ml.GetFloat() * g_pGameRules->GetDamageMultiplier() / 4, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ), tr.endpos, 128, CLASS_NONE, NULL );
# endif
}
}
if ( bHit )
{
if ( bDamageTime )
{
m_bIsFiring = true ;
m_flLastHitTime = gpGlobals - > curtime ;
m_flTargetChainsawPitch = 0.0f ;
# ifndef CLIENT_DLL
pMarine - > OnWeaponFired ( this , 1 ) ;
# endif
if ( ! pMarine - > IsAlive ( ) )
return ;
// uses 5 ammo/second
if ( gpGlobals - > curtime > = m_flAmmoUseTime )
{
// chainsaw no longer uses ammo
m_flAmmoUseTime = gpGlobals - > curtime + 0.2 ;
/*
// decrement ammo
//m_iClip1 -= 1;
# ifdef GAME_DLL
CASW_Marine * pMarine = GetMarine ( ) ;
if ( pMarine & & m_iClip1 < = 0 & & pMarine - > GetAmmoCount ( m_iPrimaryAmmoType ) < = 0 )
{
// check he doesn't have ammo in an ammo bay
CASW_Weapon_Ammo_Bag * pAmmoBag = dynamic_cast < CASW_Weapon_Ammo_Bag * > ( pMarine - > GetASWWeapon ( 0 ) ) ;
if ( ! pAmmoBag )
pAmmoBag = dynamic_cast < CASW_Weapon_Ammo_Bag * > ( pMarine - > GetASWWeapon ( 1 ) ) ;
if ( ! pAmmoBag | | ! pAmmoBag - > CanGiveAmmoToWeapon ( this ) )
pMarine - > GetMarineSpeech ( ) - > Chatter ( CHATTER_NO_AMMO ) ;
}
# endif
*/
}
m_flDmgTime = gpGlobals - > curtime + ASW_CHAINSAW_DISCHARGE_INTERVAL ;
if ( m_flShakeTime < gpGlobals - > curtime )
{
CASW_Player * pPlayer = pMarine - > GetCommander ( ) ;
if ( pPlayer & & pMarine - > IsInhabited ( ) )
{
// #ifndef CLIENT_DLL
// if (gpGlobals->maxClients == 1) // only shake the screen from the server in singleplayer (in multi it'll be predicted)
// {
// ASW_TransmitShakeEvent( pPlayer, 5.0f, 100.0f, 1.75f, SHAKE_START );
// }
// #else
// ASW_TransmitShakeEvent( pPlayer, 5.0f, 100.0f, 1.75f, SHAKE_START );
// #endif
}
m_flShakeTime = gpGlobals - > curtime + 0.5 ;
}
}
Vector vecUp , vecRight ;
QAngle angDir ;
VectorAngles ( vecDir , angDir ) ;
AngleVectors ( angDir , NULL , & vecRight , & vecUp ) ;
Vector tmpSrc = vecOrigSrc + ( vecUp * - 8 ) + ( vecRight * 3 ) ;
//UTIL_ImpactTrace( &tr, DMG_SLASH );
UpdateEffect ( tmpSrc , tr . endpos ) ;
}
}
void CASW_Weapon_Chainsaw : : UpdateEffect ( const Vector & startPoint , const Vector & endPoint )
{
//if ( !m_hBeam )
//{
//CreateEffect();
//}
//if ( m_hBeam )
//{
//m_hBeam->SetStartPos( endPoint );
//}
CASW_Marine * pOwner = GetMarine ( ) ;
if ( ! pOwner )
return ;
// make sparks come out at end point
Vector vecNormal = startPoint - endPoint ;
vecNormal . NormalizeInPlace ( ) ;
# ifndef CLIENT_DLL
CEffectData data ;
data . m_vOrigin = endPoint ;
data . m_vNormal = vecNormal ;
CPASFilter filter ( data . m_vOrigin ) ;
filter . SetIgnorePredictionCull ( true ) ;
if ( gpGlobals - > maxClients > 1 & & pOwner - > IsInhabited ( ) & & pOwner - > GetCommander ( ) )
{
// multiplayer game, where this marine is currently being controlled by a client, who will spawn his own effect
// so just make the beam effect for all other clients
filter . RemoveRecipient ( pOwner - > GetCommander ( ) ) ;
}
DispatchEffect ( filter , 0.0 , " ASWWelderSparks " , data ) ;
# else
FX_Sparks ( endPoint , 1 , 2 , vecNormal , 5 , 32 , 160 ) ;
# endif
if ( m_hNoise )
{
m_hNoise - > SetStartPos ( endPoint ) ;
}
}
void CASW_Weapon_Chainsaw : : CreateEffect ( void )
{
# ifndef CLIENT_DLL
CASW_Marine * pMarine = GetMarine ( ) ;
if ( ! pMarine )
{
return ;
}
DestroyEffect ( ) ;
m_hBeam = CBeam : : BeamCreate ( ASW_CHAINSAW_BEAM_SPRITE , 1.75 ) ;
m_hBeam - > PointEntInit ( GetAbsOrigin ( ) , this ) ;
m_hBeam - > SetBeamFlags ( FBEAM_SINENOISE ) ;
m_hBeam - > SetEndAttachment ( 1 ) ;
m_hBeam - > AddSpawnFlags ( SF_BEAM_TEMPORARY ) ; // Flag these to be destroyed on save/restore or level transition
m_hBeam - > SetOwnerEntity ( pMarine ) ;
m_hBeam - > SetScrollRate ( 10 ) ;
m_hBeam - > SetBrightness ( 200 ) ;
m_hBeam - > SetColor ( 255 , 255 , 255 ) ;
m_hBeam - > SetNoise ( 0.025 ) ;
m_hNoise = CBeam : : BeamCreate ( ASW_CHAINSAW_BEAM_SPRITE , 2.5 ) ;
m_hNoise - > PointEntInit ( GetAbsOrigin ( ) , this ) ;
m_hNoise - > SetEndAttachment ( 1 ) ;
m_hNoise - > AddSpawnFlags ( SF_BEAM_TEMPORARY ) ;
m_hNoise - > SetOwnerEntity ( pMarine ) ;
m_hNoise - > SetScrollRate ( 25 ) ;
m_hNoise - > SetBrightness ( 200 ) ;
m_hNoise - > SetColor ( 255 , 255 , 255 ) ;
m_hNoise - > SetNoise ( 0.8 ) ;
# endif
}
void CASW_Weapon_Chainsaw : : DestroyEffect ( void )
{
# ifndef CLIENT_DLL
if ( m_hBeam )
{
UTIL_Remove ( m_hBeam ) ;
m_hBeam = NULL ;
}
if ( m_hNoise )
{
UTIL_Remove ( m_hNoise ) ;
m_hNoise = NULL ;
}
# endif
}
void CASW_Weapon_Chainsaw : : EndAttack ( void )
{
if ( m_fireState ! = FIRE_OFF )
{
StartAttackOffSound ( ) ;
# ifdef CLIENT_DLL
DispatchParticleEffect ( " mining_laser_exhaust " , PATTACH_POINT_FOLLOW , this , " eject1 " ) ;
# endif
}
StopChainsawSound ( ) ;
SetWeaponIdleTime ( gpGlobals - > curtime + 2.0 ) ;
m_flNextPrimaryAttack = gpGlobals - > curtime + GetWeaponInfo ( ) - > m_flFireRate ;
m_flNextSecondaryAttack = gpGlobals - > curtime + GetWeaponInfo ( ) - > m_flFireRate ;
SetFiringState ( FIRE_OFF ) ;
ClearIsFiring ( ) ;
DestroyEffect ( ) ;
}
void CASW_Weapon_Chainsaw : : Drop ( const Vector & vecVelocity )
{
if ( m_fireState ! = FIRE_OFF )
{
EndAttack ( ) ;
}
2024-08-29 19:27:02 -04:00
StopChainsawSound ( true ) ;
StopAttackOffSound ( ) ;
StopSound ( " ASW_Chainsaw.Start " ) ;
EmitSound ( " ASW_Chainsaw.Stop " ) ;
2024-08-29 19:18:30 -04:00
BaseClass : : Drop ( vecVelocity ) ;
}
bool CASW_Weapon_Chainsaw : : Holster ( CBaseCombatWeapon * pSwitchingTo )
{
if ( m_fireState ! = FIRE_OFF )
{
EndAttack ( ) ;
}
2024-08-29 19:27:02 -04:00
StopChainsawSound ( true ) ;
StopAttackOffSound ( ) ;
StopSound ( " ASW_Chainsaw.Start " ) ;
EmitSound ( " ASW_Chainsaw.Stop " ) ;
2024-08-29 19:18:30 -04:00
return BaseClass : : Holster ( pSwitchingTo ) ;
}
void CASW_Weapon_Chainsaw : : WeaponIdle ( void )
{
if ( ! HasWeaponIdleTimeElapsed ( ) )
return ;
//Msg("%f CASW_Weapon_Chainsaw::WeaponIdle\n", gpGlobals->curtime);
float flIdleTime ;
if ( m_fireState ! = FIRE_OFF )
{
//Msg(" ending attack\n", gpGlobals->curtime);
EndAttack ( ) ;
flIdleTime = gpGlobals - > curtime + 1.4f ;
}
else
{
//Msg(" idle looping\n", gpGlobals->curtime);
//EmitSound( "ASW_Chainsaw.IdleLoop" );
flIdleTime = gpGlobals - > curtime + 1.7f ;
}
//int iAnim;
//float flRand = random->RandomFloat( 0,1 );
//if ( flRand <= 0.5 )
//{
//iAnim = ACT_VM_IDLE;
//flIdleTime = gpGlobals->curtime + 1.4f;
//}
//else
//{
//iAnim = ACT_VM_FIDGET;
//flIdleTime = gpGlobals->curtime + 3.0;
//}
//SendWeaponAnim( iAnim );
SetWeaponIdleTime ( flIdleTime ) ;
}
void CASW_Weapon_Chainsaw : : SetFiringState ( CHAINSAW_FIRE_STATE state )
{
# ifdef CLIENT_DLL
//Msg("[C] SetFiringState %d\n", state);
# else
//Msg("[C] SetFiringState %d\n", state);
# endif
m_fireState = state ;
}
bool CASW_Weapon_Chainsaw : : ShouldMarineMoveSlow ( )
{
return m_fireState ! = FIRE_OFF ;
}
# ifdef GAME_DLL
void CASW_Weapon_Chainsaw : : GetButtons ( bool & bAttack1 , bool & bAttack2 , bool & bReload , bool & bOldReload , bool & bOldAttack1 )
{
CASW_Marine * pMarine = GetMarine ( ) ;
// make AI fire this weapon whenever they have an enemy within a certain range
if ( pMarine & & ! pMarine - > IsInhabited ( ) )
{
bool bHasEnemy = ( pMarine - > GetEnemy ( ) & & pMarine - > GetEnemy ( ) - > GetAbsOrigin ( ) . DistTo ( pMarine - > GetAbsOrigin ( ) ) < 250.0f ) ;
if ( bHasEnemy )
m_fLastForcedFireTime = gpGlobals - > curtime ;
bAttack1 = ( bHasEnemy | | gpGlobals - > curtime < m_fLastForcedFireTime + 1.0f ) ; // fire for 2 seconds after killing our enemy
bAttack2 = false ;
bReload = false ;
bOldReload = false ;
return ;
}
BaseClass : : GetButtons ( bAttack1 , bAttack2 , bReload , bOldReload , bOldAttack1 ) ;
}
# endif
void CASW_Weapon_Chainsaw : : ItemPostFrame ( )
{
BaseClass : : ItemPostFrame ( ) ;
AdjustChainsawPitch ( ) ;
if ( m_fireState = = FIRE_OFF )
{
StopChainsawSound ( ) ;
}
}
ConVar asw_chainsaw_pitch_bite_rate ( " asw_chainsaw_pitch_bite_rate " , " 50.0 " , FCVAR_CHEAT | FCVAR_REPLICATED , " How quickly the chainsaw pitch changes when attack hits somethings " ) ;
ConVar asw_chainsaw_pitch_return_rate ( " asw_chainsaw_pitch_return_rate " , " 50.0 " , FCVAR_CHEAT | FCVAR_REPLICATED , " How quickly the pitch returns to normal when attacking chainsaw doesn't hit anything " ) ;
ConVar asw_chainsaw_pitch_return_delay ( " asw_chainsaw_pitch_return_delay " , " 1.0 " , FCVAR_CHEAT | FCVAR_REPLICATED , " How long after attacking something before the chainsaw pitch returns to normal " ) ;
ConVar asw_chainsaw_pitch_target ( " asw_chainsaw_pitch_target " , " 95.0 " , FCVAR_CHEAT | FCVAR_REPLICATED , " Target pitch when chainsaw starts to attack something " ) ;
ConVar asw_chainsaw_pitch_range ( " asw_chainsaw_pitch_range " , " 5.0 " , FCVAR_CHEAT | FCVAR_REPLICATED , " Random variation applied above and below target pitch " ) ;
ConVar asw_chainsaw_attack_fade_time ( " asw_chainsaw_attack_fade_time " , " 0.5 " , FCVAR_CHEAT | FCVAR_REPLICATED , " Time for chainsaw attack sound to fade out " ) ;
ConVar asw_chainsaw_shake_amplitude ( " asw_chainsaw_shake_amplitude " , " 12.5 " , FCVAR_CHEAT | FCVAR_REPLICATED ) ;
ConVar asw_chainsaw_shake_frequency ( " asw_chainsaw_shake_frequency " , " 100.0 " , FCVAR_CHEAT | FCVAR_REPLICATED ) ;
ConVar asw_chainsaw_debug ( " asw_chainsaw_debug " , " 0 " , FCVAR_CHEAT | FCVAR_REPLICATED ) ;
# ifdef CLIENT_DLL
ConVar asw_chainsaw_shake_duration ( " asw_chainsaw_shake_duration " , " 1.0 " , FCVAR_CHEAT ) ;
# endif
void CASW_Weapon_Chainsaw : : AdjustChainsawPitch ( )
{
if ( ! m_pChainsawAttackSound )
{
if ( asw_chainsaw_debug . GetBool ( ) )
{
Msg ( " No chainsaw attack sound, aborting \n " ) ;
}
return ;
}
// Translated into the pitch values as represented in the soundscripts that would mean roughly that you
// change the pitch value to randomly land between 85 and 90. (Pitch value 100 equals no change. Pitch value 50 is one octave lower.)
// The pitch down should happen over 100 milliseconds. 400 ms later (half as second after the impact triggered the pitch down)
// reset to the original pitch value over 250 ms.
float flTransitionRate = 50.0f ;
// check for returning to normal pitch
if ( ( gpGlobals - > curtime - m_flLastHitTime ) > asw_chainsaw_pitch_return_delay . GetFloat ( ) )
{
m_flTargetChainsawPitch = 100.0f ;
flTransitionRate = asw_chainsaw_pitch_return_rate . GetFloat ( ) ;
}
else if ( m_flTargetChainsawPitch = = 0.0f ) // just started attacking something
{
float flPitchMin = asw_chainsaw_pitch_target . GetFloat ( ) - asw_chainsaw_pitch_range . GetFloat ( ) ;
float flPitchMax = asw_chainsaw_pitch_target . GetFloat ( ) + asw_chainsaw_pitch_range . GetFloat ( ) ;
if ( asw_chainsaw_debug . GetBool ( ) )
{
Msg ( " pitch min/max( %f %f ) \n " , flPitchMin , flPitchMax ) ;
}
m_flTargetChainsawPitch = RandomFloat ( flPitchMin , flPitchMax ) ;
flTransitionRate = asw_chainsaw_pitch_bite_rate . GetFloat ( ) ;
# ifdef CLIENT_DLL
2024-08-29 19:33:14 -04:00
if ( ! ( prediction & & prediction - > InPrediction ( ) & & ! prediction - > IsFirstTimePredicted ( ) ) )
{
// move this somewhere else....
ScreenShake_t shake ;
shake . command = SHAKE_STOP ;
shake . amplitude = 0 ;
2024-08-29 19:18:30 -04:00
2024-08-29 19:33:14 -04:00
HACK_GETLOCALPLAYER_GUARD ( " ASW_AdjustChainsawPitch " ) ;
GetViewEffects ( ) - > Shake ( shake ) ;
2024-08-29 19:18:30 -04:00
2024-08-29 19:33:14 -04:00
shake . command = SHAKE_START ;
shake . amplitude = asw_chainsaw_shake_amplitude . GetFloat ( ) ;
shake . frequency = asw_chainsaw_shake_frequency . GetFloat ( ) ;
shake . duration = asw_chainsaw_shake_duration . GetFloat ( ) ;
2024-08-29 19:18:30 -04:00
2024-08-29 19:33:14 -04:00
GetViewEffects ( ) - > Shake ( shake ) ;
}
2024-08-29 19:18:30 -04:00
# endif
}
float flCurPitch = CSoundEnvelopeController : : GetController ( ) . SoundGetPitch ( m_pChainsawAttackSound ) ;
if ( flCurPitch ! = m_flTargetChainsawPitch )
{
if ( asw_chainsaw_debug . GetBool ( ) )
{
Msg ( " Changing chainsaw pitch to %f transition rate %f \n " , m_flTargetChainsawPitch , flTransitionRate ) ;
}
flCurPitch = Approach ( m_flTargetChainsawPitch , flCurPitch , flTransitionRate * gpGlobals - > curtime ) ;
CSoundEnvelopeController : : GetController ( ) . SoundChangePitch ( m_pChainsawAttackSound , flCurPitch , 0.0f ) ;
}
}
void CASW_Weapon_Chainsaw : : StartChainsawSound ( )
{
if ( ! m_pChainsawAttackSound )
{
if ( asw_chainsaw_debug . GetBool ( ) )
{
DevMsg ( " Start Chainsaw Attach Sound \n " ) ;
}
StopSound ( " ASW_Chainsaw.Start " ) ;
CPASAttenuationFilter filter ( this ) ;
m_pChainsawAttackSound = CSoundEnvelopeController : : GetController ( ) . SoundCreate ( filter , entindex ( ) , " ASW_Chainsaw.attackOn " ) ;
CSoundEnvelopeController : : GetController ( ) . Play ( m_pChainsawAttackSound , 1.0 , 100 ) ;
}
else
{
float fVolume = CSoundEnvelopeController : : GetController ( ) . SoundGetVolume ( m_pChainsawAttackSound ) ;
if ( fVolume < 1.0f )
{
CSoundEnvelopeController : : GetController ( ) . SoundChangeVolume ( m_pChainsawAttackSound , Approach ( 1.0f , fVolume , ( 1.0f / asw_chainsaw_attack_fade_time . GetFloat ( ) ) * gpGlobals - > frametime ) , 0.0f ) ;
}
}
}
2024-08-29 19:27:02 -04:00
void CASW_Weapon_Chainsaw : : StopChainsawSound ( bool bForce /*= false*/ )
2024-08-29 19:18:30 -04:00
{
if ( m_pChainsawAttackSound )
{
if ( asw_chainsaw_debug . GetBool ( ) )
{
DevMsg ( " Stop Chainsaw Attach Sound \n " ) ;
}
2024-08-29 19:27:02 -04:00
float fVolume = bForce ? 0.0f : CSoundEnvelopeController : : GetController ( ) . SoundGetVolume ( m_pChainsawAttackSound ) ;
2024-08-29 19:18:30 -04:00
if ( fVolume = = 0.0f )
{
CSoundEnvelopeController : : GetController ( ) . SoundDestroy ( m_pChainsawAttackSound ) ;
m_pChainsawAttackSound = NULL ;
}
else
{
CSoundEnvelopeController : : GetController ( ) . SoundChangeVolume ( m_pChainsawAttackSound , Approach ( 0.0f , fVolume , ( 1.0f / asw_chainsaw_attack_fade_time . GetFloat ( ) ) * gpGlobals - > frametime ) , 0.0f ) ;
}
}
}
void CASW_Weapon_Chainsaw : : StartAttackOffSound ( )
{
float flCurPitch = 100 ;
if ( m_pChainsawAttackSound )
{
if ( asw_chainsaw_debug . GetBool ( ) )
{
DevMsg ( " Start Chainsaw Off Sound \n " ) ;
}
flCurPitch = CSoundEnvelopeController : : GetController ( ) . SoundGetPitch ( m_pChainsawAttackSound ) ;
}
if ( ! m_pChainsawAttackOffSound )
{
CPASAttenuationFilter filter ( this ) ;
m_pChainsawAttackOffSound = CSoundEnvelopeController : : GetController ( ) . SoundCreate ( filter , entindex ( ) , " ASW_Chainsaw.attackOff " ) ;
CSoundEnvelopeController : : GetController ( ) . Play ( m_pChainsawAttackOffSound , 0.0 , flCurPitch ) ;
}
CSoundEnvelopeController : : GetController ( ) . SoundChangeVolume ( m_pChainsawAttackOffSound , 1.0 , asw_chainsaw_attack_fade_time . GetFloat ( ) ) ;
CSoundEnvelopeController : : GetController ( ) . SoundChangePitch ( m_pChainsawAttackOffSound , 100 , 1.0f / asw_chainsaw_pitch_return_rate . GetFloat ( ) ) ;
}
void CASW_Weapon_Chainsaw : : StopAttackOffSound ( )
{
if ( m_pChainsawAttackOffSound )
{
if ( asw_chainsaw_debug . GetBool ( ) )
{
DevMsg ( " Stop Chainsaw Off Sound \n " ) ;
}
CSoundEnvelopeController : : GetController ( ) . SoundDestroy ( m_pChainsawAttackOffSound ) ;
m_pChainsawAttackOffSound = NULL ;
}
}
# define ASW_CHAINSAW_SYNC_KILL_RANGE 60
bool CASW_Weapon_Chainsaw : : CheckSyncKill ( byte & forced_action , short & sync_kill_ent )
{
// sync kills disabled
return false ;
/*
// If not firing, don't do anything
if ( ! IsFiring ( ) ) //m_fireState <= FIRE_OFF
return false ;
// check for enemies in front of the player
CASW_Marine * pMarine = GetMarine ( ) ;
if ( ! pMarine )
return false ;
if ( pMarine - > GetCurrentMeleeAttack ( ) )
return false ;
Vector vecSrc = pMarine - > Weapon_ShootPosition ( ) ;
Vector vecDir ;
AngleVectors ( pMarine - > EyeAngles ( ) , & vecDir ) ;
Vector vecDest = vecSrc + ( vecDir * ASW_CHAINSAW_SYNC_KILL_RANGE ) ;
trace_t tr ;
UTIL_TraceHull ( vecSrc , vecDest , Vector ( - 5 , - 5 , - 5 ) , Vector ( 5 , 5 , 5 ) , MASK_SHOT , pMarine , COLLISION_GROUP_NONE , & tr ) ;
if ( tr . fraction < 1.0f & & tr . m_pEnt & & tr . m_pEnt - > Classify ( ) = = CLASS_ASW_DRONE )
{
forced_action = FORCED_ACTION_CHAINSAW_SYNC_KILL ;
sync_kill_ent = tr . m_pEnt - > entindex ( ) ;
return true ;
}
return false ;
*/
}