//----------------------------------------------------------------------------- // 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; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_EntityFlame::UpdateHitBoxFlames( void ) { C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating) { return; } if (pAnimating->GetModel() != m_pCachedModel) { if (m_pCachedModel != NULL) { // The model changed, we must reattach the flames. DeleteHitBoxFlames(); AttachToHitBoxes(); } if (m_pCachedModel == NULL) { // We tried to reattach and failed. 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; } 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 ); for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) { Vector vecAbsOrigin; VectorTransform(m_vecFireOrigin[i], *hitboxbones[m_nHitbox[i]], vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin(vecAbsOrigin); } }