|
|
//========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
//
//=============================================================================//
#include "cbase.h"
#include "shot_manipulator.h"
#include "paint_sprayer_shared.h"
#include "debugoverlay_shared.h"
#include "paint_stream_manager.h"
#ifdef CLIENT_DLL
#include "c_paint_sprayer.h"
#else
#include "paint_sprayer.h"
#endif
ConVar debug_paint_sprayer_cone("debug_paint_sprayer_cone", "0", FCVAR_REPLICATED | FCVAR_CHEAT); ConVar max_noisy_blobs_per_second("max_noisy_blobs_per_second", "5.0f", FCVAR_REPLICATED | FCVAR_CHEAT);
float const MAX_SPRAYER_SPREAD_ANGLE = 89.f;
void CPaintSprayer::SprayPaint( float flDeltaTime ) { CPaintStream *pPaintStream = m_hPaintStream; if ( !pPaintStream ) return;
//Don't spray silent blobs on the clients
if( m_bSilent && gpGlobals->IsClient() ) { return; }
if( flDeltaTime <= 0.0f ) { return; }
Vector vecSprayDir; AngleVectors( GetAbsAngles(), &vecSprayDir );
m_flAccumulatedTime += flDeltaTime;
const float fireDeltaTime = 1.0f / m_flBlobsPerSecond; int blobsFired = 0;
while ( m_flAccumulatedTime > fireDeltaTime ) { m_flAccumulatedTime -= fireDeltaTime;
if ( pPaintStream->GetBlobsCount() >= m_nMaxBlobCount ) continue;
CPaintBlob *pBlob = FirePaintBlob( GetAbsOrigin(), GetAbsOrigin(), GetAbsVelocity(), vecSprayDir, m_PaintPowerType, m_flBlobSpreadRadius, m_flBlobSpreadAngle, m_flMinSpeed, m_flMaxSpeed, m_flStreakPercentage, m_flMinStreakTime, m_flMaxStreakTime, m_flMinStreakSpeedDampen, m_flMaxStreakSpeedDampen, m_bSilent, m_bDrawOnly, pPaintStream, m_nBlobRandomSeed );
if( pBlob ) { m_flPercentageSinceLastNoisyBlob += m_flNoisyBlobPercentage; if( m_flPercentageSinceLastNoisyBlob >= 1.0f ) { m_flPercentageSinceLastNoisyBlob = 0.0f; pBlob->SetShouldPlaySound( !m_bSilent ); } }
pPaintStream->AddPaintBlob( pBlob );
++m_nBlobRandomSeed; ++blobsFired; }
// Note: Assume that if the sprayer is dripping, it's not spawning more than
// one blob per frame and also that, if it did, we wouldn't want more
// than one drip sound playing from the same position in a frame or within
// a fraction of a second in general. That takes this conditional out of
// the loop above.
#ifdef GAME_DLL
if( !m_bSilent && blobsFired > 0 && m_nAmbientSound == PAINT_SPRAYER_SOUND_DRIP ) { CBroadcastRecipientFilter filter; CBaseEntity::EmitSound( filter, entindex(), "Paint.Drip", &GetAbsOrigin() ); } #endif
}
CPaintBlob* FirePaintBlob( const Vector& vecSourcePosition, const Vector& vecOldSourcePosition, const Vector& vecSourceVelocity, const Vector& vecSprayDir, int paintType, float flBlobSpreadRadius, float flBlobSpreadAngle, float flMinSpeed, float flMaxSpeed, float flBlobStreakPercent, float flMinStreakTime, float flMaxStreakTime, float flMinStreakSpeedDampen, float flMaxStreakSpeedDampen, bool bSilent, bool bDrawOnly, CBaseEntity *pOwner, int nRandomSeed /*= 0*/ ) { #ifdef CLIENT_DLL
// if the client is listen server, don't create blobs twice, we don't want to double the work
if ( engine->IsClientLocalToActiveServer() ) return NULL; #endif
// set random seed
RandomSeed( nRandomSeed );
// clamp spread angle
flBlobSpreadAngle = clamp( flBlobSpreadAngle, 0.f, MAX_SPRAYER_SPREAD_ANGLE );
// random position inside the circle area
Vector vecCircleRight, vecCircleUp; VectorVectors( vecSprayDir, vecCircleRight, vecCircleUp ); vecCircleUp.NormalizeInPlace(); VMatrix matRotate; MatrixBuildRotationAboutAxis( matRotate, vecSprayDir, RandomFloat( 0.f, 360.f ) ); Vector vecBlobFirePos = vecSourcePosition + RandomFloat( 0.f, flBlobSpreadRadius ) * ( matRotate * vecCircleUp );
// compute cone origin
float flDistanceToConeOrigin = 1.f; Vector vecConeOrigin; if ( AlmostEqual( flBlobSpreadAngle, 0.f ) ) { vecConeOrigin = vecBlobFirePos - flDistanceToConeOrigin * vecSprayDir.Normalized(); } else { flDistanceToConeOrigin = flBlobSpreadRadius / tanf( DEG2RAD( flBlobSpreadAngle ) ); vecConeOrigin = vecSourcePosition - flDistanceToConeOrigin * vecSprayDir.Normalized(); }
// compute direction from random position
Vector vecBlobFireDir = vecBlobFirePos - vecConeOrigin; if ( AlmostEqual( flBlobSpreadRadius, 0.f ) ) { float flSpread = sin( DEG2RAD( flBlobSpreadAngle )/2.0f ); Vector vecSpraySpread( flSpread, flSpread, flSpread ); CShotManipulator shotManipulator( vecSprayDir ); vecBlobFireDir = shotManipulator.ApplySpread( vecSpraySpread ); } vecBlobFireDir.NormalizeInPlace();
if ( debug_paint_sprayer_cone.GetBool() ) { QAngle debugAngle; VectorAngles( vecSprayDir, debugAngle ); #ifdef CLIENT_DLL
NDebugOverlay::Circle( vecSourcePosition, debugAngle, flBlobSpreadRadius, 255, 0, 0, 128, true, 0.1f ); NDebugOverlay::Line( vecBlobFirePos, vecBlobFirePos + 20 * vecBlobFireDir, 255, 255, 0, true, 1.f ); #else
NDebugOverlay::Circle( vecSourcePosition, debugAngle, flBlobSpreadRadius, 0, 255, 0, 128, true, 0.1f ); NDebugOverlay::Line( vecBlobFirePos, vecBlobFirePos + 20 * vecBlobFireDir, 0, 255, 255, true, 1.f ); #endif
}
Vector vecBlobVelocity = vecBlobFireDir * RandomFloat( flMinSpeed, flMaxSpeed ) + vecSourceVelocity;
//The streaking values of the blob
float flStreakTime = 0.0f; float flStreakSpeedDampen = 0.0f; bool bShouldStreak = ( RandomFloat( 0.0f, 1.0f ) * 100.0f ) <= flBlobStreakPercent; if( bShouldStreak ) { flStreakTime = RandomFloat( flMinStreakTime, flMaxStreakTime ); flStreakSpeedDampen = RandomFloat( flMinStreakSpeedDampen, flMaxStreakSpeedDampen ); }
CPaintBlob *pBlob = PaintStreamManager.AllocatePaintBlob( bSilent ); if ( pBlob ) { pBlob->Init( vecBlobFirePos, vecBlobVelocity, paintType, flStreakTime, flStreakSpeedDampen, pOwner, bSilent, bDrawOnly ); }
return pBlob; }
|