示例#1
0
//-----------------------------------------------------------------------------
// Purpose: Breaks the breakable. m_hBreaker is the entity that caused us to break.
//-----------------------------------------------------------------------------
void CBreakable::Die( void )
{
	Vector vecVelocity;// shard velocity
	char cFlag = 0;
	int pitch;
	float fvol;
	
	pitch = 95 + random->RandomInt(0,29);

	if (pitch > 97 && pitch < 103)
	{
		pitch = 100;
	}

	// The more negative m_iHealth, the louder
	// the sound should be.

	fvol = random->RandomFloat(0.85, 1.0) + (abs(m_iHealth) / 100.0);
	if (fvol > 1.0)
	{
		fvol = 1.0;
	}

	const char *soundname = NULL;

	switch (m_Material)
	{
	default:
		break;

	case matGlass:
		soundname = "Breakable.Glass";
		cFlag = BREAK_GLASS;
		break;

	case matWood:
		soundname = "Breakable.Crate";
		cFlag = BREAK_WOOD;
		break;

	case matComputer:
		soundname = "Breakable.Computer";
		cFlag = BREAK_METAL;
		break;

	case matMetal:
		soundname = "Breakable.Metal";
		cFlag = BREAK_METAL;
		break;

	case matFlesh:
	case matWeb:
		soundname = "Breakable.Flesh";
		cFlag = BREAK_FLESH;
		break;

	case matRocks:
	case matCinderBlock:
		soundname = "Breakable.Concrete";
		cFlag = BREAK_CONCRETE;
		break;

	case matCeilingTile:
		soundname = "Breakable.Ceiling";
		break;
	}

	if ( soundname )
	{
		if ( m_hBreaker && m_hBreaker->IsPlayer() )
		{
			IGameEvent * event = gameeventmanager->CreateEvent( "break_breakable" );
			if ( event )
			{
				event->SetInt( "userid", ToBasePlayer( m_hBreaker )->GetUserID() );
				event->SetInt( "entindex", entindex() );
				event->SetInt( "material", cFlag );
				gameeventmanager->FireEvent( event );
			}
		}

		CSoundParameters params;
		if ( GetParametersForSound( soundname, params, NULL ) )
		{
			CPASAttenuationFilter filter( this );

			EmitSound_t ep;
			ep.m_nChannel = params.channel;
			ep.m_pSoundName = params.soundname;
			ep.m_flVolume = fvol;
			ep.m_SoundLevel = params.soundlevel;
			ep.m_nPitch = pitch;

			EmitSound( filter, entindex(), ep );	
		}
	}
		
	switch( m_Explosion )
	{
	case expDirected:
		vecVelocity = g_vecAttackDir * -200;
		break;

	case expUsePrecise:
		{
			AngleVectors( m_GibDir, &vecVelocity, NULL, NULL );
			vecVelocity *= 200;
		}
		break;

	case expRandom:
		vecVelocity.x = 0;
		vecVelocity.y = 0;
		vecVelocity.z = 0;
		break;

	default:
		DevMsg("**ERROR - Unspecified gib dir method in func_breakable!\n");
		break;
	}

	Vector vecSpot = WorldSpaceCenter();
	CPVSFilter filter2( vecSpot );

	int iModelIndex = 0;
	CCollisionProperty *pCollisionProp = CollisionProp();

	Vector vSize = pCollisionProp->OBBSize();
	int iCount = ( vSize[0] * vSize[1] + vSize[1] * vSize[2] + vSize[2] * vSize[0] ) / ( 3 * 12 * 12 );

	if ( iCount > func_break_max_pieces.GetInt() )
	{
		iCount = func_break_max_pieces.GetInt();
	}

	ConVarRef breakable_disable_gib_limit( "breakable_disable_gib_limit" );
	if ( !breakable_disable_gib_limit.GetBool() && iCount )
	{
		if ( m_PerformanceMode == PM_NO_GIBS )
		{
			iCount = 0;
		}
		else if ( m_PerformanceMode == PM_REDUCED_GIBS )
		{
			int iNewCount = iCount * func_break_reduction_factor.GetFloat();
			iCount = MAX( iNewCount, 1 );
		}
	}

	if ( m_iszModelName != NULL_STRING )
	{
		for ( int i = 0; i < iCount; i++ )
		{

	#ifdef HL1_DLL
			// Use the passed model instead of the propdata type
			const char *modelName = STRING( m_iszModelName );
			
			// if the map specifies a model by name
			if( strstr( modelName, ".mdl" ) != NULL )
			{
				iModelIndex = modelinfo->GetModelIndex( modelName );
			}
			else	// do the hl2 / normal way
	#endif

			iModelIndex = modelinfo->GetModelIndex( g_PropDataSystem.GetRandomChunkModel(  STRING( m_iszModelName ) ) );

			// All objects except the first one in this run are marked as slaves...
			int slaveFlag = 0;
			if ( i != 0 )
			{
				slaveFlag = BREAK_SLAVE;
			}

			te->BreakModel( filter2, 0.0, 
				vecSpot, pCollisionProp->GetCollisionAngles(), vSize, 
				vecVelocity, iModelIndex, 100, 1, 2.5, cFlag | slaveFlag );
		}
	}

	ResetOnGroundFlags();

	// Don't fire something that could fire myself
	SetName( NULL_STRING );

	AddSolidFlags( FSOLID_NOT_SOLID );
	
	// Fire targets on break
	m_OnBreak.FireOutput( m_hBreaker, this );

	VPhysicsDestroyObject();
	SetThink( &CBreakable::SUB_Remove );
	SetNextThink( gpGlobals->curtime + 0.1f );
	if ( m_iszSpawnObject != NULL_STRING )
	{
		CBaseEntity::Create( STRING(m_iszSpawnObject), vecSpot, pCollisionProp->GetCollisionAngles(), this );
	}

	if ( Explodable() )
	{
		ExplosionCreate( vecSpot, pCollisionProp->GetCollisionAngles(), this, GetExplosiveDamage(), GetExplosiveRadius(), true );
	}
}
//------------------------------------------------------------------------------
// Purpose: Break into panels
// Input  : pBreaker - 
//			vDir - 
//-----------------------------------------------------------------------------
void CBreakableSurface::Die( CBaseEntity *pBreaker, const Vector &vAttackDir )
{
	if ( m_bIsBroken )
		return;

	// Play a break sound
	PhysBreakSound( this, VPhysicsGetObject(), GetAbsOrigin() );

	m_bIsBroken = true;
	m_iHealth = 0.0f;

	if (pBreaker)
	{
		m_OnBreak.FireOutput( pBreaker, this );
	}
	else
	{
		m_OnBreak.FireOutput( this, this );
	}

	float flDir = -1;

	if ( vAttackDir.LengthSqr() > 0.001 )
	{
		float flDot = DotProduct( m_vNormal, vAttackDir );
		if (flDot < 0)
		{
			m_vLLVertex += m_vNormal;
			m_vLRVertex += m_vNormal;
			m_vULVertex += m_vNormal;
			m_vURVertex += m_vNormal;
			m_vNormal	*= -1;
			flDir		=   1;
		}
	}

	// -------------------------------------------------------
	// The surface has two sides, when we are killed pick 
	// the side that the damage came from 
	// -------------------------------------------------------
	Vector vWidth		= m_vLLVertex - m_vLRVertex;
	Vector vHeight		= m_vLLVertex - m_vULVertex;
	CrossProduct( vWidth, vHeight, m_vNormal.GetForModify() );
	VectorNormalize(m_vNormal.GetForModify());

	// ---------------------------------------------------
	//  Make sure width and height are oriented correctly
	// ---------------------------------------------------
	QAngle vAngles;
	VectorAngles(-1*m_vNormal,vAngles);
	Vector vWidthDir,vHeightDir;
	AngleVectors(vAngles,NULL,&vWidthDir,&vHeightDir);

	float flWDist = DotProduct(vWidthDir,vWidth);
	if (fabs(flWDist)<0.5)
	{
		Vector vSaveHeight	= vHeight;
		vHeight				= vWidth * flDir;
		vWidth				= vSaveHeight * flDir;
	}

	// -------------------------------------------------
	// Find which corner to use
	// -------------------------------------------------
	bool bLeft  = (DotProduct(vWidthDir,vWidth)   < 0);
	bool bLower = (DotProduct(vHeightDir,vHeight) < 0);
	if (bLeft)
	{
		m_vCorner = bLower ? m_vLLVertex : m_vULVertex;
	}
	else 
	{
		m_vCorner = bLower ? m_vLRVertex : m_vURVertex;
	}

	// -------------------------------------------------
	//  Calculate the number of panels
	// -------------------------------------------------
	float flWidth		= vWidth.Length();
	float flHeight		= vHeight.Length();
	m_nNumWide			= flWidth  / WINDOW_PANEL_SIZE;
	m_nNumHigh			= flHeight / WINDOW_PANEL_SIZE;

	// If to many panels make panel size bigger
	if (m_nNumWide > MAX_NUM_PANELS) m_nNumWide = MAX_NUM_PANELS;
	if (m_nNumHigh > MAX_NUM_PANELS) m_nNumHigh = MAX_NUM_PANELS;

	m_flPanelWidth	= flWidth  / m_nNumWide;
	m_flPanelHeight	= flHeight / m_nNumHigh;
	
	// Initialize panels
	for (int w=0;w<MAX_NUM_PANELS;w++)
	{ 
		for (int h=0;h<MAX_NUM_PANELS;h++)
		{
			SetSupport( w, h, WINDOW_PANE_HEALTHY );
		}
	}

	// Reset onground flags for any entity that may 
	// have been standing on me
	ResetOnGroundFlags();

	VPhysicsDestroyObject();
	AddSolidFlags( FSOLID_TRIGGER );
	AddSolidFlags( FSOLID_NOT_SOLID );
	SetTouch(&CBreakableSurface::SurfaceTouch);
}