//======================================================================================================================
// PARTICLE SYSTEM DISPATCH EFFECT
//======================================================================================================================
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void ParticleEffectCallback( const CEffectData &data )
{
	if ( SuppressingParticleEffects() )
		return; // this needs to be before using data.m_nHitBox, since that may be a serialized value that's past the end of the current particle system string table

	const char *pszName = GetParticleSystemNameFromIndex( data.m_nHitBox );

	if ( data.m_fFlags & PARTICLE_DISPATCH_FROM_ENTITY )
	{
		if ( data.m_hEntity.Get() )
		{
			C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity );
			if ( pEnt && !pEnt->IsDormant() )
			{
				if ( data.m_fFlags & PARTICLE_DISPATCH_RESET_PARTICLES )
				{
					pEnt->ParticleProp()->StopEmission();
				}

				CSmartPtr<CNewParticleEffect> pEffect = pEnt->ParticleProp()->Create( pszName, (ParticleAttachment_t)data.m_nDamageType, data.m_nAttachmentIndex );
				AssertMsg2( pEffect.IsValid() && pEffect->IsValid(), "%s could not create particle effect %s",
					C_BaseEntity::Instance( data.m_hEntity )->GetDebugName(), pszName );
				if ( pEffect.IsValid() && pEffect->IsValid() )
				{
					if ( (ParticleAttachment_t)data.m_nDamageType == PATTACH_CUSTOMORIGIN )
					{
						pEffect->SetSortOrigin( data.m_vOrigin );
						pEffect->SetControlPoint( 0, data.m_vOrigin );
						pEffect->SetControlPoint( 1, data.m_vStart );
						Vector vecForward, vecRight, vecUp;
						AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp );
						pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
					}
				}
			}
		}
	}	
	else
	{
		CSmartPtr<CNewParticleEffect> pEffect = CNewParticleEffect::Create( NULL, pszName );
		if ( pEffect->IsValid() )
		{
			pEffect->SetSortOrigin( data.m_vOrigin );
			pEffect->SetControlPoint( 0, data.m_vOrigin );
			pEffect->SetControlPoint( 1, data.m_vStart );
			Vector vecForward, vecRight, vecUp;
			AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp );
			pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ParticleSystem::ClientThink( void )
{
	if ( m_bActive )
	{
		const char *pszName = GetParticleSystemNameFromIndex( m_iEffectIndex );
		if ( pszName && pszName[0] )
		{
			CNewParticleEffect *pEffect = ParticleProp()->Create( pszName, PATTACH_ABSORIGIN_FOLLOW );
			AssertMsg1( pEffect, "Particle system couldn't make %s", pszName );
			if (pEffect)
			{
				for ( int i = 0 ; i < kMAXCONTROLPOINTS ; ++i )
				{
					CBaseEntity *pOnEntity = m_hControlPointEnts[i].Get();
					if ( pOnEntity )
					{
						ParticleProp()->AddControlPoint( pEffect, i + 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW );
					}

					AssertMsg2( m_iControlPointParents[i] >= 0 && m_iControlPointParents[i] <= kMAXCONTROLPOINTS ,
						"Particle system specified bogus control point parent (%d) for point %d.",
						m_iControlPointParents[i], i );

					if (m_iControlPointParents[i] != 0)
					{
						pEffect->SetControlPointParent(i+1, m_iControlPointParents[i]);
					}
				}

				// NOTE: What we really want here is to compare our lifetime and that of our children and see if this delta is
				//		 already past the end of it, denoting that we're finished.  In that case, just destroy us and be done. -- jdw

				// TODO: This can go when the SkipToTime code below goes
				ParticleProp()->OnParticleSystemUpdated( pEffect, 0.0f );

				// Skip the effect ahead if we're restarting it
				float flTimeDelta = gpGlobals->curtime - m_flStartTime;
				if ( flTimeDelta > 0.01f )
				{
					VPROF_BUDGET( "C_ParticleSystem::ClientThink SkipToTime", "Particle Simulation" );
					pEffect->SkipToTime( flTimeDelta );
				}
			}
		}
	}
}
Example #3
0
float CASW_DamageAllocationMgr::Allocate( IndexType_t iTarget, CBaseEntity *pProjectile, float flDamage )
{
	if ( !IsValid( iTarget ) )
		return 0;

	Rebuild( iTarget );

	AssertMsg2( !IsProjectileForTarget( iTarget, pProjectile ), "Double-allocated %s to %s\n", pProjectile->GetDebugName(), 
		iTarget->m_hTargeted->GetDebugName() );

	tuple_t * RESTRICT ptarget = &Elem(iTarget);

	ProjectilePool_t::IndexLocalType_t projIdx = m_ProjectileLists.Alloc( true );
	m_ProjectileLists[projIdx].m_hHandle = pProjectile; 
	m_ProjectileLists[projIdx].m_flDamage = flDamage; 

	if ( m_ProjectileLists.IsValidIndex(ptarget->m_nProjectiles) )
	{
		m_ProjectileLists.LinkBefore( ptarget->m_nProjectiles, projIdx );
	}

	ptarget->m_nProjectiles = projIdx;
	return ptarget->m_flAccumulatedDamage += flDamage;
}
Example #4
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_ParticleSystem::ClientThink( void )
{
	if ( m_bActive )
	{
		const char *pszName = GetParticleSystemNameFromIndex( m_iEffectIndex );
		if ( pszName && pszName[0] )
		{
			CNewParticleEffect *pEffect = ParticleProp()->Create( pszName, PATTACH_ABSORIGIN_FOLLOW );
			m_pEffect = pEffect;
	
			if (pEffect)
			{
				for ( int i = 0 ; i < kMAXCONTROLPOINTS ; ++i )
				{
					CBaseEntity *pOnEntity = m_hControlPointEnts[i].Get();
					if ( pOnEntity )
					{
						ParticleProp()->AddControlPoint( pEffect, i + 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW );
					}

					AssertMsg2( m_iControlPointParents[i] >= 0 && m_iControlPointParents[i] <= kMAXCONTROLPOINTS ,
						"Particle system specified bogus control point parent (%d) for point %d.",
						m_iControlPointParents[i], i );

					if (m_iControlPointParents[i] != 0)
					{
						pEffect->SetControlPointParent(i+1, m_iControlPointParents[i]);
					}
				}

				//server controlled control points (variables in particle effects instead of literal follow points)
				for( int i = 0; i != ARRAYSIZE( m_iServerControlPointAssignments ); ++i )
				{
					if( m_iServerControlPointAssignments[i] != 255 )
					{
						pEffect->SetControlPoint( m_iServerControlPointAssignments[i], m_vServerControlPoints[i] );
					}
					else
					{
						break;
					}
				}

				// Attach our particle snapshot if we have one
				Assert( m_pSnapshot || !m_szSnapshotFileName[0] ); // m_szSnapshotFileName shouldn't change after the create update
				if ( m_pSnapshot )
				{
					pEffect->SetControlPointSnapshot( 0, m_pSnapshot );
				}

				// NOTE: What we really want here is to compare our lifetime and that of our children and see if this delta is
				//		 already past the end of it, denoting that we're finished.  In that case, just destroy us and be done. -- jdw

				// TODO: This can go when the SkipToTime code below goes
				ParticleProp()->OnParticleSystemUpdated( pEffect, 0.0f );

				// Skip the effect ahead if we're restarting it
				float flTimeDelta = gpGlobals->curtime - m_flStartTime;
				if ( flTimeDelta > 0.01f )
				{
					VPROF_BUDGET( "C_ParticleSystem::ClientThink SkipToTime", "Particle Simulation" );
					pEffect->SkipToTime( flTimeDelta );
				}
			}
		}
	}
}
int CPhysicsSurfaceProps::ParseSurfaceData(const char* pFilename, const char* pTextfile) {
	if (!AddFileToDatabase(pFilename)) return 0;

	KeyValues* surfprops = new KeyValues("");
	surfprops->LoadFromBuffer(pFilename, pTextfile);
	for (KeyValues* surface = surfprops; surface; surface = surface->GetNextKey()) {
		CSurface prop;
		int baseMaterial = GetSurfaceIndex("default");

		memset(&prop.data, 0, sizeof(prop.data));
		prop.m_name = m_strings->AddString(surface->GetName());
		prop.data.game.material = 0;
		prop.data.game.maxSpeedFactor = 1.0f;
		prop.data.game.jumpFactor = 1.0f;
		prop.data.game.climbable = 0.0f;
		CopyPhysicsProperties(&prop, baseMaterial);

		for (KeyValues* data = surface->GetFirstSubKey(); data; data = data->GetNextKey()) {
			const char* key = data->GetName();
			if (!strcmpi(key, "base")) {
				baseMaterial = GetSurfaceIndex(data->GetString());
				CopyPhysicsProperties(&prop, baseMaterial);
			} else if (!strcmpi(key, "thickness")) {
				prop.data.physics.thickness = data->GetFloat();
			} else if (!strcmpi(key, "density")) {
				prop.data.physics.density = data->GetFloat();
			} else if (!strcmpi(key, "elasticity")) {
				prop.data.physics.elasticity = data->GetFloat();
			} else if (!strcmpi(key, "friction")) {
				prop.data.physics.friction = data->GetFloat();
			} else if (!strcmpi(key, "dampening")) {
				prop.data.physics.dampening = data->GetFloat();
			} else if (!strcmpi(key, "audioreflectivity")) {
				prop.data.audio.reflectivity = data->GetFloat();
			} else if (!strcmpi(key, "audiohardnessfactor")) {
				prop.data.audio.hardnessFactor = data->GetFloat();
			} else if (!strcmpi(key, "audioroughnessfactor")) {
				prop.data.audio.roughnessFactor = data->GetFloat();
			} else if (!strcmpi(key, "scrapeRoughThreshold")) {
				prop.data.audio.roughThreshold = data->GetFloat();
			} else if (!strcmpi(key, "impactHardThreshold")) {
				prop.data.audio.hardThreshold = data->GetFloat();
			} else if (!strcmpi(key, "audioHardMinVelocity")) {
				prop.data.audio.hardVelocityThreshold = data->GetFloat();
			} else if (!strcmpi(key, "maxspeedfactor")) {
				prop.data.game.maxSpeedFactor = data->GetFloat();
			} else if (!strcmpi(key, "jumpfactor")) {
				prop.data.game.jumpFactor = data->GetFloat();
			} else if (!strcmpi(key, "climbable")) {
				prop.data.game.climbable = data->GetInt();
			} else if (!strcmpi(key, "gamematerial")) {
				if (data->GetDataType() == KeyValues::TYPE_STRING && strlen(data->GetString()) == 1) {
					prop.data.game.material = toupper(data->GetString()[0]);
				} else {
					prop.data.game.material = data->GetInt();
				}
			} else if (!strcmpi(key, "stepleft")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.stepleft = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "stepright")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.stepright = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "impactsoft")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.impactSoft = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "impacthard")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.impactHard = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "scrapesmooth")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.scrapeSmooth = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "scraperough")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.scrapeRough = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "bulletimpact")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.bulletImpact = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "break")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.breakSound = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "strain")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.strainSound = m_soundList.AddToTail(sym);
			} else if (!strcmpi(key, "rolling")) {
				CUtlSymbol sym = m_strings->AddString(data->GetString());
				prop.data.sounds.rolling = m_soundList.AddToTail(sym);
			} else {
				AssertMsg2(0, "Bad surfaceprop key %s (%s)\n", key, data->GetString());
			}
		}
		if (GetSurfaceIndex(m_strings->String(prop.m_name)) >= 0) break;

		m_props.AddToTail(prop);
	}
	surfprops->deleteThis();
	return 0;
}
Example #6
0
// Pick a sequence for the given activity. If the current sequence is appropriate for the 
// current activity, and its stored weight is negative (whatever that means), always select
// it. Otherwise perform a weighted selection -- imagine a large roulette wheel, with each
// sequence having a number of spaces corresponding to its weight.
int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence )
{
	// is the current sequence appropriate?
	if (curSequence >= 0)
	{
		mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( curSequence );

		if (seqdesc.activity == activity && seqdesc.actweight < 0)
			return curSequence;
	}

	if ( !pstudiohdr->SequencesAvailable() )
	{
		return ACTIVITY_NOT_AVAILABLE;
	}

	if ( pstudiohdr->GetNumSeq() == 1 )
	{
		AssertMsg( 0, "Expected single sequence case to be handled in ::SelectWeightedSequence()" );
		return ACTIVITY_NOT_AVAILABLE;
	}

	if (!ValidateAgainst(pstudiohdr))
	{
		AssertMsg1(false, "CStudioHdr %s has changed its vmodel pointer without reinitializing its activity mapping! Now performing emergency reinitialization.", pstudiohdr->pszName());
		ExecuteOnce(DebuggerBreakIfDebugging());
		Reinitialize(pstudiohdr);
	}

	// a null m_pSequenceTuples just means that this studio header has no activities.
	if (!m_pSequenceTuples)
		return ACTIVITY_NOT_AVAILABLE;

	// get the data for the given activity
	HashValueType dummy( activity, 0, 0, 0 );
	UtlHashHandle_t handle = m_ActToSeqHash.Find(dummy);
	if (!m_ActToSeqHash.IsValidHandle(handle))
	{
		return ACTIVITY_NOT_AVAILABLE;
	}
	const HashValueType * __restrict actData = &m_ActToSeqHash[handle];

	AssertMsg2( actData->totalWeight > 0, "Activity %s has total weight of %d!",
		activity, actData->totalWeight );
	int weighttotal = actData->totalWeight;

	// failsafe if the weight is 0: assume the artist screwed up and that the first sequence
	// for this activity should be returned.
	int randomValue = 0;
	if ( actData->totalWeight <= 0 )
	{
		Warning( "Activity %s has %d sequences with a total weight of %d!", ActivityList_NameForIndex(activity), actData->count, actData->totalWeight );
		return (m_pSequenceTuples + actData->startingIdx)->seqnum;
	}
	else if ( actData->totalWeight == 1 )
	{
		randomValue = 0;
	}
	else
	{
		// generate a random number from 0 to the total weight
		if ( IsInPrediction() )
		{
			randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1 );
		}
		else
		{
			randomValue = RandomInt( 0, weighttotal - 1 );
		}
	}


	// chug through the entries in the list (they are sequential therefore cache-coherent)
	// until we run out of random juice
	SequenceTuple * __restrict sequenceInfo = m_pSequenceTuples + actData->startingIdx;

	const SequenceTuple *const stopHere = sequenceInfo + actData->count; // this is a backup 
		// in case the weights are somehow miscalculated -- we don't read or write through
		// it (because it aliases the restricted pointer above); it's only here for 
		// the comparison.

	while (randomValue >= sequenceInfo->weight && sequenceInfo < stopHere)
	{
		randomValue -= sequenceInfo->weight;
		++sequenceInfo;
	}

	return sequenceInfo->seqnum;

}