bool C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) { bool bRet = true; if ( !ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt ) ) bRet = false; GetRagdollCurSequenceWithDeathPose( this, pDeltaBones1, gpGlobals->curtime, m_iDeathPose, m_iDeathFrame ); float ragdollCreateTime = PhysGetSyncCreateTime(); if ( ragdollCreateTime != gpGlobals->curtime ) { // The next simulation frame begins before the end of this frame // so initialize the ragdoll at that time so that it will reach the current // position at curtime. Otherwise the ragdoll will simulate forward from curtime // and pop into the future a bit at this point of transition if ( !ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime ) ) bRet = false; } else { if ( !SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ) ) bRet = false; } return bRet; }
int C_FirstpersonBody::DrawModel( int flags ) { const int viewId = CurrentViewID(); if ( viewId == VIEW_SHADOW_DEPTH_TEXTURE && !C_GstringPlayer::ShouldFirstpersonModelCastShadow() || viewId == VIEW_MONITOR ) { return 0; } if ( viewId == VIEW_REFLECTION ) { const Vector &vecViewOrigin( CurrentViewOrigin() ); VisibleFogVolumeInfo_t fogVolumeInfo; render->GetVisibleFogVolume( vecViewOrigin, &fogVolumeInfo ); if ( fogVolumeInfo.m_nVisibleFogVolume >= 0 ) { if ( fogVolumeInfo.m_flWaterHeight - vecViewOrigin.z > -25.0f ) { return 0; } } } if ( IsInThirdPersonView() ) { m_bBonescalingEnabled = false; } { CBaseAnimating::AutoAllowBoneAccess boneAccess( true, false ); InvalidateBoneCache(); SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); } int ret = BaseClass::DrawModel( flags ); m_bBonescalingEnabled = true; return ret; }
void C_ClientPartialRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) { BaseClass::ImpactTrace( pTrace, iDamageType, pCustomImpactName ); // client entities have the network index -1 so lots of effects don't work easily if ( BloodColor() != DONT_BLEED ) { const char *pszDecalName = NULL; switch ( BloodColor() ) { case BLOOD_COLOR_RED: pszDecalName = "Blood"; break; } int index = decalsystem->GetDecalIndexForName( pszDecalName ); Vector vecDir = pTrace->endpos - pTrace->startpos; if ( vecDir.LengthSqr() > FLT_EPSILON ) { vecDir.NormalizeInPlace(); } if ( index >= 0 ) { SetShrinkingEnabled( false ); InvalidateBoneCache(); SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); // add decal to model AddDecal( pTrace->startpos, pTrace->endpos, pTrace->endpos, pTrace->hitbox, index, false, *pTrace ); SetShrinkingEnabled( true ); InvalidateBoneCache(); } // add decal to world trace_t tr; UTIL_TraceLine( pTrace->endpos, pTrace->endpos + vecDir * 35.0f, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); UTIL_BloodDecalTrace( &tr, BloodColor() ); if ( ShouldCreateBloodParticles() ) { UTIL_BloodImpact( pTrace->endpos, -vecDir, BloodColor(), 5 ); } } if ( m_bReleaseRagdoll || m_bFadingOut ) return; const float flGibbingChance = ( ( iDamageType & DMG_BLAST ) != 0 ) ? gstring_gibbing_explosion_chance.GetFloat() : gstring_gibbing_chance.GetFloat(); const bool bSniperImpact = ( iDamageType & DMG_SNIPER ) != 0; if ( !bSniperImpact && RandomFloat() > flGibbingChance / 100.0f ) return; CStudioHdr *pHdr = GetModelPtr(); if ( pHdr == NULL ) return; int iStudioBone = ConvertPhysBoneToStudioBone( this, pTrace->physicsbone ); const bool bExplosionImpact = ( iDamageType & DMG_BLAST ) != 0; // if the hit bone is a valid studio bone and we know that this bone // is drawn as a normal bone (not shrunken) if ( iStudioBone >= 0 && m_normalBones.IsBitSet( iStudioBone ) || bExplosionImpact ) { CUtlVector< ragdollparams_partial_t > gibModels; // we've been analysed already so use the known hit group // and try recusive splitting GibbingParamsRecursive_t params; params.pHdr = pHdr; params.pszHitBone = ( iStudioBone >= 0 && !bExplosionImpact ) ? pHdr->pBone( iStudioBone )->pszName() : NULL; params.pszParentName = STRING( m_strRecursiveParent ); params.pszRootBone = ( m_iBranchRootBone >= 0 && m_iBranchRootBone < pHdr->numbones() ) ? pHdr->pBone( m_iBranchRootBone )->pszName() : NULL; params.pJointBones = &m_jointBones; const char *pszParentSplitBone; // find a suitable joint to cut if ( C_GibConfig::GetInstance()->GetGibsForGroup( params, gibModels, &pszParentSplitBone ) || bExplosionImpact && C_GibConfig::GetInstance()->GetRandomGibsForGroup( params, gibModels, &pszParentSplitBone ) ) { int iSplitboneIndex = Studio_BoneIndexByName( pHdr, pszParentSplitBone ); // don't do cutting if we cut this joint in the past // or if this joint is our current branch root if ( iSplitboneIndex < 0 || m_jointBones.IsBitSet( iSplitboneIndex ) || m_iBranchRootBone == iSplitboneIndex ) return; matrix3x4_t boneDelta0[MAXSTUDIOBONES]; matrix3x4_t boneDelta1[MAXSTUDIOBONES]; matrix3x4_t currentBones[MAXSTUDIOBONES]; const float boneDt = 0.1f; // setup bones without shrinking to position the new gibs SetShrinkingEnabled( false ); GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); SetShrinkingEnabled( true ); InvalidateBoneCache(); // create the new gibmodels FOR_EACH_VEC( gibModels, i ) { ragdollparams_partial_t &partial = gibModels[ i ]; // add old trunk joints for ( int iBit = m_jointBones.FindNextSetBit( 0 ); iBit >= 0; iBit = m_jointBones.FindNextSetBit( iBit + 1 ) ) { if ( m_iBranchRootBone == iBit ) continue; const char *pszName = pHdr->pBone( iBit )->pszName(); partial.trunkBones.AddToTail( pszName ); } // if we create a trunk from an existing branch // we have to propagate the branch root bone if ( partial.rootBone.IsEmpty() && m_iBranchRootBone >= 0 ) { partial.rootBone = pHdr->pBone( m_iBranchRootBone )->pszName(); } C_BaseAnimating *pGib = CreateRagdollCopy( false ); C_ClientPartialRagdoll *pRecursiveRagdoll = dynamic_cast< C_ClientPartialRagdoll* >( pGib ); Assert( pRecursiveRagdoll ); // apply force and propagate cut information if ( pRecursiveRagdoll != NULL ) { pRecursiveRagdoll->SetRecursiveGibData( STRING( m_strRecursiveParent ), STRING( m_strRecursiveGoreName ), STRING( m_strRecursiveGoreMaterialName ) ); pRecursiveRagdoll->SetShrinkingEnabled( true ); Vector vecDelta = pTrace->endpos - pTrace->startpos; if ( vecDelta.LengthSqr() <= FLT_EPSILON ) { vecDelta = RandomVector( -1, 1 ); } vecDelta.NormalizeInPlace(); pRecursiveRagdoll->m_vecForce = vecDelta * RandomFloat( 15000.0f, 35000.0f ); pRecursiveRagdoll->m_nForceBone = pTrace->physicsbone; pRecursiveRagdoll->SetBloodColor( BloodColor() ); pRecursiveRagdoll->m_jointBones.Or( m_jointBones, &pRecursiveRagdoll->m_jointBones ); //FOR_EACH_VEC( m_Gore, i ) //{ // const int iBone = m_Gore[ i ].m_iBone; // if ( iBone >= 0 && iBone == m_iBranchRootBone ) // { // } // pRecursiveRagdoll->m_Gore.AddToTail( m_Gore[ i ] ); // m_Gore.Remove( i ); // i--; //} } pGib->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt, false, &partial ); if ( bExplosionImpact && RandomFloat() <= gstring_gibbing_explosion_recursive_chance.GetFloat() / 100.0f ) { pGib->ImpactTrace( pTrace, iDamageType, pCustomImpactName ); } if ( BloodColor() == BLOOD_COLOR_RED && ( !pRecursiveRagdoll || !pRecursiveRagdoll->m_bReleaseRagdoll ) && ShouldCreateBloodParticles() ) { Assert( pszParentSplitBone != NULL ); DispatchGibParticle( pGib, pszParentSplitBone, bExplosionImpact, BloodColor() ); } }