//----------------------------------------------------------------------------- // 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); }