#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" #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(pMarine->GetASWWeapon(0)); if (!pAmmoBag) pAmmoBag = dynamic_cast(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(); } else { StopChainsawSound(); StopAttackOffSound(); StopSound( "ASW_Chainsaw.Start" ); EmitSound( "ASW_Chainsaw.Stop" ); } BaseClass::Drop( vecVelocity ); } bool CASW_Weapon_Chainsaw::Holster( CBaseCombatWeapon *pSwitchingTo ) { if (m_fireState != FIRE_OFF) { EndAttack(); } else { StopChainsawSound(); StopAttackOffSound(); StopSound( "ASW_Chainsaw.Start" ); EmitSound( "ASW_Chainsaw.Stop" ); } 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 // move this somewhere else.... ScreenShake_t shake; shake.command = SHAKE_STOP; shake.amplitude = 0; HACK_GETLOCALPLAYER_GUARD( "ASW_AdjustChainsawPitch" ); GetViewEffects()->Shake( shake ); 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(); GetViewEffects()->Shake( shake ); #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 ); } } } void CASW_Weapon_Chainsaw::StopChainsawSound() { if ( m_pChainsawAttackSound ) { if ( asw_chainsaw_debug.GetBool() ) { DevMsg( "Stop Chainsaw Attach Sound\n" ); } float fVolume = CSoundEnvelopeController::GetController().SoundGetVolume( m_pChainsawAttackSound ); 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; */ }