// // Sticky gib puts blood on the wall and stays put. // void CGib::StickyGibTouch ( CBaseEntity *pOther ) { Vector vecSpot; trace_t tr; SetThink ( &CGib::SUB_Remove ); SetNextThink( gpGlobals->curtime + 10 ); if ( !FClassnameIs( pOther, "worldspawn" ) ) { SetNextThink( gpGlobals->curtime ); return; } UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + GetAbsVelocity() * 32, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); UTIL_BloodDecalTrace( &tr, m_bloodColor ); Vector vecForward = tr.plane.normal * -1; QAngle angles; VectorAngles( vecForward, angles ); SetLocalAngles( angles ); SetAbsVelocity( vec3_origin ); SetLocalAngularVelocity( vec3_angle ); SetMoveType( MOVETYPE_NONE ); }
void CCineBlood :: BloodGush ( void ) { Vector vecSplatDir; TraceResult tr; pev->nextthink = gpGlobals->time + 0.1; UTIL_MakeVectors(pev->angles); if ( pev->health-- < 0 ) REMOVE_ENTITY(ENT(pev)); // CHANGE_METHOD ( ENT(pev), em_think, SUB_Remove ); if ( RANDOM_FLOAT ( 0 , 1 ) < 0.7 )// larger chance of globs { UTIL_BloodDrips( pev->origin, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 10 ); } else// slim chance of geyser { UTIL_BloodStream( pev->origin, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, RANDOM_LONG(50, 150) ); } if ( RANDOM_FLOAT ( 0, 1 ) < 0.75 ) { // decals the floor with blood. vecSplatDir = Vector ( 0 , 0 , -1 ); vecSplatDir = vecSplatDir + (RANDOM_FLOAT(-1,1) * 0.6 * gpGlobals->v_right) + (RANDOM_FLOAT(-1,1) * 0.6 * gpGlobals->v_forward);// randomize a bit UTIL_TraceLine( pev->origin + Vector ( 0, 0 , 64) , pev->origin + vecSplatDir * 256, ignore_monsters, ENT(pev), &tr); if ( tr.flFraction != 1.0 ) { // Decal with a bloodsplat UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); } } }
// Sticky gib puts blood on the wall and stays put. void CGib::StickyGibTouch(CBaseEntity *pOther) { Vector vecSpot; TraceResult tr; SetThink(&CBaseEntity::SUB_Remove); pev->nextthink = gpGlobals->time + 10; if (!FClassnameIs(pOther->pev, "worldspawn")) { pev->nextthink = gpGlobals->time; return; } vecSpot = pev->origin + pev->velocity * 32; UTIL_TraceLine(pev->origin, vecSpot, ignore_monsters, ENT(pev), &tr); UTIL_BloodDecalTrace(&tr, m_bloodColor); pev->velocity = tr.vecPlaneNormal * -1; pev->angles = UTIL_VecToAngles(pev->velocity); pev->velocity = g_vecZero; pev->avelocity = g_vecZero; pev->movetype = MOVETYPE_NONE; }
void CGib::BounceGibTouch(CBaseEntity *pOther) { if (pev->flags & FL_ONGROUND) { pev->velocity = pev->velocity * 0.9; pev->angles.x = 0; pev->angles.z = 0; pev->avelocity.x = 0; pev->avelocity.z = 0; } else { if (g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED) { TraceResult tr; Vector vecSpot = pev->origin + Vector(0, 0, 8); UTIL_TraceLine(vecSpot, vecSpot + Vector(0, 0, -24), ignore_monsters, ENT(pev), &tr); UTIL_BloodDecalTrace(&tr, m_bloodColor); m_cBloodDecals--; } if (m_material != matNone && !RANDOM_LONG(0, 2)) { float zvel = Q_fabs(pev->velocity.z); float volume = 0.8 * Q_min(1.0f, zvel / 450); CBreakable::MaterialSoundRandom(edict(), (Materials)m_material, volume); } } }
NOXREF void CBaseMonster::MakeDamageBloodDecal(int cCount, float flNoise, TraceResult *ptr, Vector &vecDir) { // make blood decal on the wall! TraceResult Bloodtr; Vector vecTraceDir; int i; if (!IsAlive()) { // dealing with a dead monster. if (pev->max_health <= 0) { // no blood decal for a monster that has already decalled its limit. return; } else pev->max_health--; } for (i = 0; i < cCount; ++i) { vecTraceDir = vecDir; vecTraceDir.x += RANDOM_FLOAT(-flNoise, flNoise); vecTraceDir.y += RANDOM_FLOAT(-flNoise, flNoise); vecTraceDir.z += RANDOM_FLOAT(-flNoise, flNoise); UTIL_TraceLine(ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172, ignore_monsters, ENT(pev), &Bloodtr); if (Bloodtr.flFraction != 1.0f) { UTIL_BloodDecalTrace(&Bloodtr, BloodColor()); } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pOther - //----------------------------------------------------------------------------- void C_PhysPropClientside::HitSurface( C_BaseEntity *pOther ) { if ( HasInteraction( PROPINTER_WORLD_BLOODSPLAT ) ) { trace_t tr; tr = BaseClass::GetTouchTrace(); if ( tr.m_pEnt ) { UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); } } }
void CBaseEntity::__MAKE_VHOOK(TraceBleed)(float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { if (BloodColor() == DONT_BLEED) return; if (!flDamage) return; if (!(bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR))) return; // make blood decal on the wall! TraceResult Bloodtr; Vector vecTraceDir; float flNoise; int cCount; int i; if (flDamage < 10.0f) { flNoise = 0.1f; cCount = 1; } else if (flDamage < 25.0f) { flNoise = 0.2f; cCount = 2; } else { flNoise = 0.3f; cCount = 4; } for (i = 0; i < cCount; ++i) { // trace in the opposite direction the shot came from (the direction the shot is going) vecTraceDir = vecDir * -1.0f; vecTraceDir.x += RANDOM_FLOAT(-flNoise, flNoise); vecTraceDir.y += RANDOM_FLOAT(-flNoise, flNoise); vecTraceDir.z += RANDOM_FLOAT(-flNoise, flNoise); UTIL_TraceLine(ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172.0f, ignore_monsters, ENT(pev), &Bloodtr); if (Bloodtr.flFraction != 1.0f) { if (!RANDOM_LONG(0, 2)) { UTIL_BloodDecalTrace(&Bloodtr, BloodColor()); } } } }
//========================================================= //========================================================= void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { // make blood decal on the wall! TraceResult Bloodtr; Vector vecTraceDir; int i; if ( !IsAlive() ) { // dealing with a dead monster. if ( pev->max_health <= 0 ) { // no blood decal for a monster that has already decalled its limit. return; } else { pev->max_health--; } } for ( i = 0 ; i < cCount ; i++ ) { vecTraceDir = vecDir; vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172, ignore_monsters, ENT(pev), &Bloodtr); /* MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); WRITE_BYTE( TE_SHOWLINE); WRITE_COORD( ptr->vecEndPos.x ); WRITE_COORD( ptr->vecEndPos.y ); WRITE_COORD( ptr->vecEndPos.z ); WRITE_COORD( Bloodtr.vecEndPos.x ); WRITE_COORD( Bloodtr.vecEndPos.y ); WRITE_COORD( Bloodtr.vecEndPos.z ); MESSAGE_END(); */ if ( Bloodtr.flFraction != 1.0 ) { UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); } } }
// // Gib bounces on the ground or wall, sponges some blood down, too! // void CGib::BounceGibTouch ( CBaseEntity *pOther ) { Vector vecSpot; trace_t tr; IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( pPhysics ) return; //if ( random->RandomInt(0,1) ) // return;// don't bleed everytime if (GetFlags() & FL_ONGROUND) { SetAbsVelocity( GetAbsVelocity() * 0.9 ); QAngle angles = GetLocalAngles(); angles.x = 0; angles.z = 0; SetLocalAngles( angles ); QAngle angVel = GetLocalAngularVelocity(); angVel.x = 0; angVel.z = 0; SetLocalAngularVelocity( vec3_angle ); } else { //City17: Germany Violence Fix. if ( /*g_Language.GetInt() != LANGUAGE_GERMAN &&*/ m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED ) { vecSpot = GetAbsOrigin() + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); UTIL_BloodDecalTrace( &tr, m_bloodColor ); m_cBloodDecals--; } if ( m_material != matNone && random->RandomInt(0,2) == 0 ) { float volume; float zvel = fabs(GetAbsVelocity().z); volume = 0.8f * min(1.0, ((float)zvel) / 450.0f); CBreakable::MaterialSoundRandom( entindex(), (Materials)m_material, volume ); } } }
void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if ( pev->spawnflags & SF_BLOOD_STREAM ) UTIL_BloodStream( BloodPosition(pActivator), Direction(), Color(), BloodAmount() ); else UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), BloodAmount() ); if ( pev->spawnflags & SF_BLOOD_DECAL ) { Vector forward = Direction(); Vector start = BloodPosition( pActivator ); TraceResult tr; UTIL_TraceLine( start, start + forward * BloodAmount() * 2, ignore_monsters, NULL, &tr ); if ( tr.flFraction != 1.0 ) UTIL_BloodDecalTrace( &tr, Color() ); } }
// // Gib bounces on the ground or wall, sponges some blood down, too! // void CGib :: BounceGibTouch ( CBaseEntity *pOther ) { Vector vecSpot; TraceResult tr; //if ( RANDOM_LONG(0,1) ) // return;// don't bleed everytime if (pev->flags & FL_ONGROUND) { pev->velocity = pev->velocity * 0.9; pev->angles.x = 0; pev->angles.z = 0; pev->avelocity.x = 0; pev->avelocity.z = 0; } else { if ( g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED ) { vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); UTIL_BloodDecalTrace( &tr, m_bloodColor ); m_cBloodDecals--; } if ( m_material != matNone && RANDOM_LONG(0,2) == 0 ) { float volume; float zvel = fabs(pev->velocity.z); volume = 0.8 * min(1.0, ((float)zvel) / 450.0); CBreakable::MaterialSoundRandom( edict(), (Materials)m_material, volume ); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CAntlionGrub::MakeSquashDecals( const Vector &vecOrigin ) { trace_t tr; Vector vecStart; Vector vecTraceDir; GetVectors( NULL, NULL, &vecTraceDir ); vecTraceDir.Negate(); for ( int i = 0 ; i < 8; i++ ) { vecStart.x = vecOrigin.x + random->RandomFloat( -16.0f, 16.0f ); vecStart.y = vecOrigin.y + random->RandomFloat( -16.0f, 16.0f ); vecStart.z = vecOrigin.z + 4; UTIL_TraceLine( vecStart, vecStart + ( vecTraceDir * (5*12) ), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0 ) { UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_YELLOW ); } } }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CRagdollProp::HandleFirstCollisionInteractions( int index, gamevcollisionevent_t *pEvent ) { IPhysicsObject *pObj = VPhysicsGetObject(); if ( !pObj) return; if( HasPhysgunInteraction( "onfirstimpact", "break" ) ) { // Looks like it's best to break by having the object damage itself. CTakeDamageInfo info; info.SetDamage( m_iHealth ); info.SetAttacker( this ); info.SetInflictor( this ); info.SetDamageType( DMG_GENERIC ); Vector vecPosition; Vector vecVelocity; VPhysicsGetObject()->GetVelocity( &vecVelocity, NULL ); VPhysicsGetObject()->GetPosition( &vecPosition, NULL ); info.SetDamageForce( vecVelocity ); info.SetDamagePosition( vecPosition ); TakeDamage( info ); return; } if( HasPhysgunInteraction( "onfirstimpact", "paintsplat" ) ) { IPhysicsObject *pObj = VPhysicsGetObject(); Vector vecPos; pObj->GetPosition( &vecPos, NULL ); trace_t tr; UTIL_TraceLine( vecPos, vecPos + pEvent->preVelocity[0] * 1.5, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); switch( random->RandomInt( 1, 3 ) ) { case 1: UTIL_DecalTrace( &tr, "PaintSplatBlue" ); break; case 2: UTIL_DecalTrace( &tr, "PaintSplatGreen" ); break; case 3: UTIL_DecalTrace( &tr, "PaintSplatPink" ); break; } } bool bAlienBloodSplat = HasPhysgunInteraction( "onfirstimpact", "alienbloodsplat" ); if( bAlienBloodSplat || HasPhysgunInteraction( "onfirstimpact", "bloodsplat" ) ) { IPhysicsObject *pObj = VPhysicsGetObject(); Vector vecPos; pObj->GetPosition( &vecPos, NULL ); trace_t tr; UTIL_TraceLine( vecPos, vecPos + pEvent->preVelocity[0] * 1.5, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); UTIL_BloodDecalTrace( &tr, bAlienBloodSplat ? BLOOD_COLOR_GREEN : BLOOD_COLOR_RED ); } }
void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { if (BloodColor() == DONT_BLEED) return; if (flDamage == 0) return; if (! (bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR))) return; // make blood decal on the wall! TraceResult Bloodtr; Vector vecTraceDir; float flNoise; int cCount; int i; /* if ( !IsAlive() ) { // dealing with a dead monster. if ( pev->max_health <= 0 ) { // no blood decal for a monster that has already decalled its limit. return; } else { pev->max_health--; } } */ if (flDamage < 10) { flNoise = 0.1; cCount = 1; } else if (flDamage < 25) { flNoise = 0.2; cCount = 2; } else { flNoise = 0.3; cCount = 4; } for ( i = 0 ; i < cCount ; i++ ) { vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT(pev), &Bloodtr); if ( Bloodtr.flFraction != 1.0 ) { UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); } } }
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() ); } }
void CASW_Alien::DoBloodDecal( float flDamage, const Vector &vecPos, const Vector &vecDir, trace_t *ptr, int bitsDamageType ) { if ( ( BloodColor() == DONT_BLEED) || ( BloodColor() == BLOOD_COLOR_MECH ) ) { return; } if (flDamage == 0) return; if ( !( bitsDamageType & ( DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_AIRBOAT ) ) ) return; // make blood decal on the wall! trace_t Bloodtr; Vector vecTraceDir; float flNoise; int cCount; int i; #ifdef GAME_DLL if ( !IsAlive() ) { // dealing with a dead npc. if ( GetMaxHealth() <= 0 ) { // no blood decal for a npc that has already decalled its limit. return; } else { m_iMaxHealth -= 1; } } #endif if (flDamage < 10) { flNoise = 0.1; cCount = 1; } else if (flDamage < 25) { flNoise = 0.2; cCount = 2; } else { flNoise = 0.3; cCount = 4; } float flTraceDist = (bitsDamageType & DMG_AIRBOAT) ? 384 : 172; for ( i = 0 ; i < cCount ; i++ ) { vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) vecTraceDir.x += random->RandomFloat( -flNoise, flNoise ); vecTraceDir.y += random->RandomFloat( -flNoise, flNoise ); vecTraceDir.z += random->RandomFloat( -flNoise, flNoise ); // Don't bleed on grates. UTIL_TraceLine( vecPos, vecPos + vecTraceDir * -flTraceDist, MASK_SOLID_BRUSHONLY & ~CONTENTS_GRATE, this, COLLISION_GROUP_NONE, &Bloodtr); if ( Bloodtr.fraction != 1.0 ) { UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); } } }
static int luasrc_UTIL_BloodDecalTrace (lua_State *L) { UTIL_BloodDecalTrace(&luaL_checktrace(L, 1), luaL_checkint(L, 2)); return 0; }