void C_EntityFlame::ClientThink( void ) { for (int i = 0; i < NUM_HITBOX_FIRES; i++) { if ( m_pFireSmoke[i] != NULL ) { if ( m_pFireSmoke[i]->m_bFadingOut == false ) { m_pFireSmoke[i]->m_flScaleStart = m_pFireSmoke[i]->m_flScaleEnd; m_pFireSmoke[i]->m_flScaleEnd = 0.00001; m_pFireSmoke[i]->m_flScaleTimeStart = Helper_GetTime(); m_pFireSmoke[i]->m_flScaleTimeEnd = Helper_GetTime() + 2.0; m_pFireSmoke[i]->m_flScaleRegister = -1; m_pFireSmoke[i]->m_bFadingOut = true; } else { if ( m_pFireSmoke[i]->m_flScaleTimeEnd <= Helper_GetTime() ) { if ( m_hEntAttached ) { CPASAttenuationFilter filter( m_hEntAttached ); m_hEntAttached->EmitSound( filter, m_hEntAttached->GetSoundSourceIndex(), "General.StopBurning" ); } CleanUpRagdollOnRemove(); Release(); return; } } } } SetNextClientThink( gpGlobals->curtime + 0.1f ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_FireSmoke::UpdateScale( void ) { float time = Helper_GetTime(); if ( m_flScaleRegister != m_flScaleEnd ) { //See if we're done scaling if ( time > m_flScaleTimeEnd ) { m_flScaleRegister = m_flStartScale = m_flScaleEnd; } else { //Lerp the scale and set it float timeFraction = 1.0f - ( m_flScaleTimeEnd - time ) / ( m_flScaleTimeEnd - m_flScaleTimeStart ); float newScale = 0.0f; if ( m_bFadingOut == false ) newScale = m_flScaleStart + ( ( m_flScaleEnd - m_flScaleStart ) * timeFraction ); else newScale = m_flScaleStart - ( ( m_flScaleStart - m_flScaleEnd ) * timeFraction ); m_flScaleRegister = m_flStartScale = newScale; } } }
//----------------------------------------------------------------------------- // Purpose: Generate a flicker value // Output : scalar value //----------------------------------------------------------------------------- float GetFlickerScale( void ) { float result = 0.0f; float time = Helper_GetTime() + m_nGUID; result = sin( time * 1000.0f ); result += 0.5f * sin( time * 2000.0f ); result -= 0.5f * cos( time * 8000.0f ); return result; }
//----------------------------------------------------------------------------- // Purpose: // Input : *pRecvProp - // *pStruct - // *pVarData - // *pIn - // objectID - //----------------------------------------------------------------------------- void RecvProxy_ScaleTime( const CRecvProxyData *pData, void *pStruct, void *pOut ) { C_FireSmoke *pFireSmoke = (C_FireSmoke *) pStruct; float time = pData->m_Value.m_Float; //If changed, update our internal information //if ( pFireSmoke->m_flScaleTime != time ) { if ( time == -1.0f ) { pFireSmoke->m_flScaleTimeStart = Helper_GetTime()-1.0f; pFireSmoke->m_flScaleTimeEnd = pFireSmoke->m_flScaleTimeStart; } else { pFireSmoke->m_flScaleTimeStart = Helper_GetTime(); pFireSmoke->m_flScaleTimeEnd = Helper_GetTime() + time; } } pFireSmoke->m_flScaleTime = time; }
//----------------------------------------------------------------------------- // Purpose: Attaches fire to the hitboxes of an animating character. The fire // is distributed based on hitbox volumes -- it attaches to the larger // hitboxes first. //----------------------------------------------------------------------------- void C_EntityFlame::AttachToHitBoxes( void ) { m_pCachedModel = NULL; C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating || !pAnimating->GetModel()) { return; } CStudioHdr *pStudioHdr = pAnimating->GetModelPtr(); if (!pStudioHdr) { return; } mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); if ( !set ) { return; } if ( !set->numhitboxes ) { return; } m_pCachedModel = pAnimating->GetModel(); CBoneCache *pCache = pAnimating->GetBoneCache( pStudioHdr ); matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() ); // // Sort the hitboxes by volume. // HitboxVolume_t hitboxvolume[MAXSTUDIOBONES]; for ( int i = 0; i < set->numhitboxes; i++ ) { mstudiobbox_t *pBox = set->pHitbox(i); hitboxvolume[i].nIndex = i; hitboxvolume[i].flVolume = CalcBoxVolume(pBox->bbmin, pBox->bbmax); } qsort(hitboxvolume, set->numhitboxes, sizeof(hitboxvolume[0]), (int (__cdecl *)(const void *, const void *))SortHitboxVolumes); // // Attach fire to the hitboxes. // for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) { int hitboxindex; // // Pick the 5 biggest hitboxes, or random ones if there are less than 5 hitboxes, // then pick random ones after that. // if (( i < 5 ) && ( i < set->numhitboxes )) { hitboxindex = i; } else { hitboxindex = random->RandomInt( 0, set->numhitboxes - 1 ); } mstudiobbox_t *pBox = set->pHitbox( hitboxvolume[hitboxindex].nIndex ); Assert( hitboxbones[pBox->bone] ); m_nHitbox[i] = hitboxvolume[hitboxindex].nIndex; m_pFireSmoke[i] = new C_FireSmoke; // // Calculate a position within the hitbox to place the fire. // m_vecFireOrigin[i] = Vector(random->RandomFloat(pBox->bbmin.x, pBox->bbmax.x), random->RandomFloat(pBox->bbmin.y, pBox->bbmax.y), random->RandomFloat(pBox->bbmin.z, pBox->bbmax.z)); Vector vecAbsOrigin; VectorTransform( m_vecFireOrigin[i], *hitboxbones[pBox->bone], vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin( vecAbsOrigin ); // // The first fire emits smoke, the rest do not. // m_pFireSmoke[i]->m_nFlags = bitsFIRESMOKE_ACTIVE; m_pFireSmoke[i]->m_nFlameModelIndex = modelinfo->GetModelIndex("sprites/fire1.vmt"); m_pFireSmoke[i]->m_nFlameFromAboveModelIndex = modelinfo->GetModelIndex("sprites/flamefromabove.vmt"); m_pFireSmoke[i]->m_flScale = 0; m_pFireSmoke[i]->m_flStartScale = 0; m_pFireSmoke[i]->m_flScaleTime = 1.5; m_pFireSmoke[i]->m_flScaleRegister = 0.1; m_pFireSmoke[i]->m_flChildFlameSpread = 20.0; m_pFireSmoke[i]->m_flScaleStart = 0; m_pFireSmoke[i]->SetOwnerEntity( this ); // Do a simple That Looks About Right clamp on the volumes // so that we don't get flames too large or too tiny. float flVolume = hitboxvolume[hitboxindex].flVolume; Assert( IsFinite(flVolume) ); #define FLAME_HITBOX_MIN_VOLUME 1000.0f #define FLAME_HITBOX_MAX_VOLUME 4000.0f if( flVolume < FLAME_HITBOX_MIN_VOLUME ) { flVolume = FLAME_HITBOX_MIN_VOLUME; } else if( flVolume > FLAME_HITBOX_MAX_VOLUME ) { flVolume = FLAME_HITBOX_MAX_VOLUME; } m_pFireSmoke[i]->m_flScaleEnd = 0.00012f * flVolume; m_pFireSmoke[i]->m_flScaleTimeStart = Helper_GetTime(); m_pFireSmoke[i]->m_flScaleTimeEnd = Helper_GetTime() + 2.0; m_pFireSmoke[i]->StartClientOnly(); } m_bAttachedToHitboxes = true; }
//----------------------------------------------------------------------------- // Purpose: Attaches fire to the hitboxes of an animating character. The fire // is distributed based on hitbox volumes -- it attaches to the larger // hitboxes first. //----------------------------------------------------------------------------- void C_EntityFlame::AttachToHitBoxes( void ) { m_pCachedModel = NULL; C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating || !pAnimating->GetModel()) { return; } studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if (!pStudioHdr) { return; } mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); if ( !set ) { return; } if ( !set->numhitboxes ) { return; } m_pCachedModel = pAnimating->GetModel(); int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT; studiocache_t *pcache = Studio_GetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask ); if ( !pcache ) { matrix3x4_t bonetoworld[MAXSTUDIOBONES]; pAnimating->SetupBones( bonetoworld, MAXSTUDIOBONES, boneMask, gpGlobals->curtime ); pcache = Studio_SetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask, bonetoworld ); } matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; Studio_LinkHitboxCache( hitboxbones, pcache, pStudioHdr, set ); // // Sort the hitboxes by volume. // HitboxVolume_t hitboxvolume[MAXSTUDIOBONES]; for ( int i = 0; i < set->numhitboxes; i++ ) { mstudiobbox_t *pBox = set->pHitbox(i); hitboxvolume[i].nIndex = i; hitboxvolume[i].flVolume = CalcBoxVolume(pBox->bbmin, pBox->bbmax); } qsort(hitboxvolume, set->numhitboxes, sizeof(hitboxvolume[0]), (int (__cdecl *)(const void *, const void *))SortHitboxVolumes); // // Attach fire to the hitboxes. // for ( i = 0; i < NUM_HITBOX_FIRES; i++ ) { // // Pick the 5 biggest hitboxes, or random ones if there are less than 5 hitboxes, // then pick random ones after that. // if (( i < 5 ) && ( i < set->numhitboxes )) { m_nHitbox[i] = hitboxvolume[i].nIndex; } else { m_nHitbox[i] = random->RandomInt( 0, set->numhitboxes - 1 ); } mstudiobbox_t *pBox = set->pHitbox(m_nHitbox[i]); m_pFireSmoke[i] = new C_FireSmoke; // // Calculate a position within the hitbox to place the fire. // m_vecFireOrigin[i] = Vector(random->RandomFloat(pBox->bbmin.x, pBox->bbmax.x), random->RandomFloat(pBox->bbmin.y, pBox->bbmax.y), random->RandomFloat(pBox->bbmin.z, pBox->bbmax.z)); Vector vecAbsOrigin; VectorTransform(m_vecFireOrigin[i], *hitboxbones[m_nHitbox[i]], vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin( vecAbsOrigin ); // // The first 2 fires emit smoke, the rest do not. // m_pFireSmoke[i]->m_nFlags = bitsFIRESMOKE_ACTIVE | bitsFIRESMOKE_GLOW; if ( i < 2 ) { m_pFireSmoke[i]->m_nFlags |= bitsFIRESMOKE_SMOKE; } m_pFireSmoke[i]->m_nFlameModelIndex = modelinfo->GetModelIndex("sprites/fire1.vmt"); m_pFireSmoke[i]->m_flScale = 0; m_pFireSmoke[i]->m_flStartScale = 0; m_pFireSmoke[i]->m_flScaleTime = 1.5; m_pFireSmoke[i]->m_flScaleRegister = 0.1; m_pFireSmoke[i]->m_flChildFlameSpread = 20.0; m_pFireSmoke[i]->m_flScaleStart = 0; m_pFireSmoke[i]->m_flScaleEnd = 0.00012f * hitboxvolume[i].flVolume; m_pFireSmoke[i]->m_flScaleTimeStart = Helper_GetTime(); m_pFireSmoke[i]->m_flScaleTimeEnd = Helper_GetTime() + 2.0; m_pFireSmoke[i]->StartClientOnly(); } m_bAttachedToHitboxes = true; }