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 CEffects::PlayerDeath(vec2 Pos, int ClientID) { vec3 BloodColor(1.0f,1.0f,1.0f); if(ClientID >= 0) { if(m_pClient->m_aClients[ClientID].m_UseCustomColor) BloodColor = m_pClient->m_pSkins->GetColorV3(m_pClient->m_aClients[ClientID].m_ColorBody); else { const CSkins::CSkin *s = m_pClient->m_pSkins->Get(m_pClient->m_aClients[ClientID].m_SkinID); if(s) BloodColor = s->m_BloodColor; } } for(int i = 0; i < 64; i++) { CParticle p; p.SetDefault(); p.m_Spr = SPRITE_PART_SPLAT01 + (rand()%3); p.m_Pos = Pos; p.m_Vel = RandomDir() * ((frandom()+0.1f)*900.0f); p.m_LifeSpan = 0.3f + frandom()*0.3f; p.m_StartSize = 24.0f + frandom()*16; p.m_EndSize = 0; p.m_Rot = frandom()*pi*2; p.m_Rotspeed = (frandom()-0.5f) * pi; p.m_Gravity = 800.0f; p.m_Friction = 0.8f; vec3 c = BloodColor * (0.75f + frandom()*0.25f); p.m_Color = vec4(c.r, c.g, c.b, 0.75f); m_pClient->m_pParticles->Add(CParticles::GROUP_GENERAL, &p); } }
void C_HL2MP_Player::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { Vector vecOrigin = ptr->endpos - vecDir * 4; float flDistance = 0.0f; if ( info.GetAttacker() ) { flDistance = (ptr->endpos - info.GetAttacker()->GetAbsOrigin()).Length(); } if ( m_takedamage ) { AddMultiDamage( info, this ); int blood = BloodColor(); CBaseEntity *pAttacker = info.GetAttacker(); if ( pAttacker ) { if ( HL2MPRules()->IsTeamplay() && pAttacker->InSameTeam( this ) == true ) return; } if ( blood != DONT_BLEED ) { SpawnBlood( vecOrigin, vecDir, blood, flDistance );// a little surface blood. TraceBleed( flDistance, vecDir, ptr, info.GetDamageType() ); } } }
//----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CHL1BaseNPC::CorpseGib( const CTakeDamageInfo &info ) { CEffectData data; data.m_vOrigin = WorldSpaceCenter(); data.m_vNormal = data.m_vOrigin - info.GetDamagePosition(); VectorNormalize( data.m_vNormal ); data.m_flScale = RemapVal( m_iHealth, 0, -500, 1, 3 ); data.m_flScale = clamp( data.m_flScale, 1, 3 ); if ( HasAlienGibs() ) data.m_nMaterial = ALIEN_GIBS; else if ( HasHumanGibs() ) data.m_nMaterial = HUMAN_GIBS; data.m_nColor = BloodColor(); DispatchEffect( "HL1Gib", data ); CSoundEnt::InsertSound( SOUND_MEAT, GetAbsOrigin(), 256, 0.5f, this ); /// BaseClass::CorpseGib( info ); return true; }
void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) { pev->model = iStringNull;// make invisible SetThink( SUB_Remove ); SetTouch( NULL ); pev->nextthink = gpGlobals->time + 0.1; // since squeak grenades never leave a body behind, clear out their takedamage now. // Squeaks do a bit of radius damage when they pop, and that radius damage will // continue to call this function unless we acknowledge the Squeak's death now. (sjb) pev->takedamage = DAMAGE_NO; // play squeek blast EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM); CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 ); UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 ); if (m_hOwner != NULL) RadiusDamage ( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST ); else RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST ); // reset owner so death message happens if (m_hOwner != NULL) pev->owner = m_hOwner->edict(); CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS ); }
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()); } } }
void CHL1NPCTalker::TraceAttack(const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator) { if ( info.GetDamage() >= 1.0 && !(info.GetDamageType() & DMG_SHOCK ) ) { UTIL_BloodImpact( ptr->endpos, vecDir, BloodColor(), 4 ); } BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator ); }
void CHL1BaseNPC::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { if ( info.GetDamage() >= 1.0 && !(info.GetDamageType() & DMG_SHOCK ) ) { UTIL_BloodSpray( ptr->endpos, vecDir, BloodColor(), 4, FX_BLOODSPRAY_ALL ); } BaseClass::TraceAttack( info, vecDir, ptr, NULL ); }
//========================================================= // TraceAttack //========================================================= void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { if ( pev->takedamage ) { SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); } }
//========================================================= //========================================================= 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() ); } } }
/* ================ TraceAttack ================ */ void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { Vector vecOrigin = ptr->vecEndPos - vecDir * 4; if ( pev->takedamage ) { AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); int blood = BloodColor(); if ( blood != DONT_BLEED ) { SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); } } }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- float CNPC_CombineS::GetHitgroupDamageMultiplier( int iHitGroup, const CTakeDamageInfo &info ) { bool isNohead = false; switch( iHitGroup ) { case HITGROUP_HEAD: int HeadshotRandom = random->RandomInt(0, 4); if (!(g_Language.GetInt() == LANGUAGE_GERMAN || UTIL_IsLowViolence()) && g_fr_headshotgore.GetBool()) { if (isNohead == false && HeadshotRandom == 0 && !(info.GetDamageType() & DMG_NEVERGIB) || isNohead == false && (info.GetDamageType() & (DMG_SNIPER | DMG_BUCKSHOT)) && !(info.GetDamageType() & DMG_NEVERGIB)) { SetModel("models/gibs/combine_soldier_beheaded.mdl"); DispatchParticleEffect("headshotspray", PATTACH_POINT_FOLLOW, this, "bloodspurt", true); SpawnBlood(GetAbsOrigin(), g_vecAttackDir, BloodColor(), info.GetDamage()); CGib::SpawnSpecificGibs(this, 6, 750, 1500, "models/gibs/pgib_p3.mdl", 6); CGib::SpawnSpecificGibs(this, 6, 750, 1500, "models/gibs/pgib_p4.mdl", 6); EmitSound("Gore.Headshot"); m_iHealth = 0; g_pGameRules->iHeadshotCount += 1; isNohead = true; CBasePlayer *pPlayer = UTIL_PlayerByIndex(1); if (g_fr_economy.GetBool()) { pPlayer->AddMoney(5); } if (!g_fr_classic.GetBool()) { pPlayer->AddXP(7); } } else { // Soldiers take double headshot damage return 2.0f; } } else { // Soldiers take double headshot damage return 2.0f; } } return BaseClass::GetHitgroupDamageMultiplier( iHitGroup, info ); }
void CNPC_AlienGrunt::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { CTakeDamageInfo ainfo = info; float flDamage = ainfo.GetDamage(); if ( ptr->hitgroup == 10 && (ainfo.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_CLUB))) { // hit armor if ( m_flDamageTime != gpGlobals->curtime || (random->RandomInt(0,10) < 1) ) { CPVSFilter filter( ptr->endpos ); te->ArmorRicochet( filter, 0.0, &ptr->endpos, &ptr->plane.normal ); m_flDamageTime = gpGlobals->curtime; } if ( random->RandomInt( 0, 1 ) == 0 ) { Vector vecTracerDir = vecDir; vecTracerDir.x += random->RandomFloat( -0.3, 0.3 ); vecTracerDir.y += random->RandomFloat( -0.3, 0.3 ); vecTracerDir.z += random->RandomFloat( -0.3, 0.3 ); vecTracerDir = vecTracerDir * -512; Vector vEndPos = ptr->endpos + vecTracerDir; UTIL_Tracer( ptr->endpos, vEndPos, ENTINDEX( edict() ) ); } flDamage -= 20; if (flDamage <= 0) flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated ainfo.SetDamage( flDamage ); } else { SpawnBlood( ptr->endpos, vecDir, BloodColor(), flDamage);// a little surface blood. TraceBleed( flDamage, vecDir, ptr, ainfo.GetDamageType() ); } AddMultiDamage( ainfo, this ); }
//========================================================= // TraceAttack //========================================================= void CAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { if ( ptr->iHitgroup == 10 && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))) { // hit armor if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) { UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); pev->dmgtime = gpGlobals->time; } if ( RANDOM_LONG( 0, 1 ) == 0 ) { Vector vecTracerDir = vecDir; vecTracerDir.x += RANDOM_FLOAT( -0.3, 0.3 ); vecTracerDir.y += RANDOM_FLOAT( -0.3, 0.3 ); vecTracerDir.z += RANDOM_FLOAT( -0.3, 0.3 ); vecTracerDir = vecTracerDir * -512; MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, ptr->vecEndPos ); WRITE_BYTE( TE_TRACER ); WRITE_COORD( ptr->vecEndPos.x ); WRITE_COORD( ptr->vecEndPos.y ); WRITE_COORD( ptr->vecEndPos.z ); WRITE_COORD( vecTracerDir.x ); WRITE_COORD( vecTracerDir.y ); WRITE_COORD( vecTracerDir.z ); MESSAGE_END(); } flDamage -= 20; if (flDamage <= 0) flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated } else { SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); } AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); }
void CNihilanth::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { if (m_irritation == 3) m_irritation = 2; if (m_irritation == 2 && ptr->iHitgroup == 2 && flDamage > 2) m_irritation = 3; if (m_irritation != 3) { Vector vecBlood = (ptr->vecEndPos - pev->origin).Normalize( ); UTIL_BloodStream( ptr->vecEndPos, vecBlood, BloodColor(), flDamage + (100 - 100 * (pev->health / gSkillData.nihilanthHealth))); } // SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage * 5.0);// a little surface blood. AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); }
void CBaseMonster::__MAKE_VHOOK(TraceAttack)(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { Vector vecOrigin = ptr->vecEndPos - vecDir * 4; if (pev->takedamage == DAMAGE_YES) { m_LastHitGroup = ptr->iHitgroup; switch (ptr->iHitgroup) { case HITGROUP_GENERIC: break; case HITGROUP_HEAD: flDamage *= 3; break; case HITGROUP_CHEST: case HITGROUP_STOMACH: flDamage *= 1.5; break; case HITGROUP_LEFTARM: case HITGROUP_RIGHTARM: flDamage *= 1.0; break; case HITGROUP_LEFTLEG: case HITGROUP_RIGHTLEG: flDamage *= 0.75; break; case HITGROUP_SHIELD: flDamage = 0; break; default: break; } AddMultiDamage(pevAttacker, this, flDamage, bitsDamageType); int blood = BloodColor(); if (blood != DONT_BLEED) { // a little surface blood. SpawnBlood(vecOrigin, blood, flDamage); } } }
void CEffects::PlayerDeath(vec2 Pos, int ClientID) { vec3 BloodColor(1.0f,1.0f,1.0f); if(ClientID >= 0) { if(m_pClient->m_GameInfo.m_GameFlags&GAMEFLAG_TEAMS) { int ColorVal = m_pClient->m_pSkins->GetTeamColor(m_pClient->m_aClients[ClientID].m_aUseCustomColors[CSkins::SKINPART_BODY], m_pClient->m_aClients[ClientID].m_aSkinPartColors[CSkins::SKINPART_BODY], m_pClient->m_aClients[ClientID].m_Team, CSkins::SKINPART_BODY); BloodColor = m_pClient->m_pSkins->GetColorV3(ColorVal); } else { if(m_pClient->m_aClients[ClientID].m_aUseCustomColors[CSkins::SKINPART_BODY]) BloodColor = m_pClient->m_pSkins->GetColorV3(m_pClient->m_aClients[ClientID].m_aSkinPartColors[CSkins::SKINPART_BODY]); else { const CSkins::CSkinPart *s = m_pClient->m_pSkins->GetSkinPart(CSkins::SKINPART_BODY, m_pClient->m_aClients[ClientID].m_SkinPartIDs[CSkins::SKINPART_BODY]); if(s) BloodColor = s->m_BloodColor; } } } for(int i = 0; i < 64; i++) { CParticle p; p.SetDefault(); p.m_Spr = SPRITE_PART_SPLAT01 + (random_int()%3); p.m_Pos = Pos; p.m_Vel = RandomDir() * ((frandom()+0.1f)*900.0f); p.m_LifeSpan = 0.3f + frandom()*0.3f; p.m_StartSize = 24.0f + frandom()*16; p.m_EndSize = 0; p.m_Rot = frandom()*pi*2; p.m_Rotspeed = (frandom()-0.5f) * pi; p.m_Gravity = 800.0f; p.m_Friction = 0.8f; vec3 c = BloodColor * (0.75f + frandom()*0.25f); p.m_Color = vec4(c.r, c.g, c.b, 0.75f); m_pClient->m_pParticles->Add(CParticles::GROUP_GENERAL, &p); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CUnitBase::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { Vector vecOrigin = ptr->endpos - vecDir * 4; if ( m_takedamage ) { AddMultiDamage( info, this ); // Must always be called from the client to save data #ifdef CLIENT_DLL int blood = BloodColor(); if ( blood != DONT_BLEED ) { SpawnBlood( vecOrigin, vecDir, blood, info.GetDamage() );// a little surface blood. TraceBleed( info.GetDamage(), vecDir, ptr, info.GetDamageType() ); } #endif // CLIENT_DLL } }
//----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CHL1NPCTalker::CorpseGib( const CTakeDamageInfo &info ) { CEffectData data; data.m_vOrigin = WorldSpaceCenter(); data.m_vNormal = data.m_vOrigin - info.GetDamagePosition(); VectorNormalize( data.m_vNormal ); data.m_flScale = RemapVal( m_iHealth, 0, -500, 1, 3 ); data.m_flScale = clamp( data.m_flScale, 1, 3 ); data.m_nMaterial = 1; data.m_nHitBox = -m_iHealth; data.m_nColor = BloodColor(); DispatchEffect( "HL1Gib", data ); CSoundEnt::InsertSound( SOUND_MEAT, GetAbsOrigin(), 256, 0.5f, this ); return true; }
//========================================================= // TraceAttack //========================================================= void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { if ( pev->takedamage ) { m_LastHitGroup = ptr->iHitgroup; switch ( ptr->iHitgroup ) { case HITGROUP_GENERIC: break; case HITGROUP_HEAD: flDamage *= gSkillData.monHead; break; case HITGROUP_CHEST: flDamage *= gSkillData.monChest; break; case HITGROUP_STOMACH: flDamage *= gSkillData.monStomach; break; case HITGROUP_LEFTARM: case HITGROUP_RIGHTARM: flDamage *= gSkillData.monArm; break; case HITGROUP_LEFTLEG: case HITGROUP_RIGHTLEG: flDamage *= gSkillData.monLeg; break; default: break; } SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : &info - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- void CNPC_CombineAce::Event_Killed( const CTakeDamageInfo &info ) { if (!(g_Language.GetInt() == LANGUAGE_GERMAN || UTIL_IsLowViolence()) && info.GetDamageType() & (DMG_BLAST | DMG_CRUSH) && !(info.GetDamageType() & (DMG_DISSOLVE)) && !PlayerHasMegaPhysCannon()) { Vector vecDamageDir = info.GetDamageForce(); SpawnBlood(GetAbsOrigin(), g_vecAttackDir, BloodColor(), info.GetDamage()); DispatchParticleEffect("headshotspray", GetAbsOrigin(), GetAbsAngles(), this); EmitSound("Gore.Headshot"); float flFadeTime = 25.0; CGib::SpawnSpecificGibs(this, 1, 750, 1500, "models/gibs/soldier_ace_head.mdl", flFadeTime); Vector vecRagForce; vecRagForce.x = random->RandomFloat(-400, 400); vecRagForce.y = random->RandomFloat(-400, 400); vecRagForce.z = random->RandomFloat(0, 250); Vector vecRagDmgForce = (vecRagForce + vecDamageDir); CBaseEntity *pLeftArmGib = CreateRagGib("models/gibs/soldier_ace_left_arm.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pLeftArmGib) { color32 color = pLeftArmGib->GetRenderColor(); pLeftArmGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pRightArmGib = CreateRagGib("models/gibs/soldier_ace_right_arm.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pRightArmGib) { color32 color = pRightArmGib->GetRenderColor(); pRightArmGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pTorsoGib = CreateRagGib("models/gibs/soldier_ace_torso.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pTorsoGib) { color32 color = pTorsoGib->GetRenderColor(); pTorsoGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pPelvisGib = CreateRagGib("models/gibs/soldier_ace_pelvis.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pPelvisGib) { color32 color = pPelvisGib->GetRenderColor(); pPelvisGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pLeftLegGib = CreateRagGib("models/gibs/soldier_ace_left_leg.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pLeftLegGib) { color32 color = pLeftLegGib->GetRenderColor(); pLeftLegGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pRightLegGib = CreateRagGib("models/gibs/soldier_ace_right_leg.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pRightLegGib) { color32 color = pRightLegGib->GetRenderColor(); pRightLegGib->SetRenderColor(color.r, color.g, color.b, color.a); } //now add smaller gibs. CGib::SpawnSpecificGibs(this, 3, 750, 1500, "models/gibs/pgib_p3.mdl", flFadeTime); CGib::SpawnSpecificGibs(this, 3, 750, 1500, "models/gibs/pgib_p4.mdl", flFadeTime); if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0) { pArmor->Remove(); DropItem("item_shield", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360)); } Vector forceVector = CalcDamageForceVector(info); // Drop any weapon that I own if (VPhysicsGetObject()) { Vector weaponForce = forceVector * VPhysicsGetObject()->GetInvMass(); Weapon_Drop(m_hActiveWeapon, NULL, &weaponForce); } else { Weapon_Drop(m_hActiveWeapon); } if (info.GetAttacker()->IsPlayer()) { ((CSingleplayRules*)GameRules())->NPCKilled(this, info); } UTIL_Remove(this); SetThink(NULL); return; } // Don't bother if we've been told not to, or the player has a megaphyscannon if ( combine_ace_spawn_health.GetBool() == false || PlayerHasMegaPhysCannon() ) { BaseClass::Event_Killed( info ); return; } SetEyeState(ACE_EYE_DEAD); if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0) { pArmor->Remove(); } CBasePlayer *pPlayer = ToBasePlayer( info.GetAttacker() ); if ( !pPlayer ) { CPropVehicleDriveable *pVehicle = dynamic_cast<CPropVehicleDriveable *>( info.GetAttacker() ) ; if ( pVehicle && pVehicle->GetDriver() && pVehicle->GetDriver()->IsPlayer() ) { pPlayer = assert_cast<CBasePlayer *>( pVehicle->GetDriver() ); } } if ( pPlayer != NULL ) { // Elites drop alt-fire ammo, so long as they weren't killed by dissolving. #ifdef HL2_EPISODIC if (HasSpawnFlags(SF_COMBINE_NO_AR2DROP) == false) #endif { if (FClassnameIs(GetActiveWeapon(), "weapon_ar2")) { CBaseEntity *pItem = DropItem("item_ammo_ar2_altfire", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360)); if (pItem) { IPhysicsObject *pObj = pItem->VPhysicsGetObject(); if (pObj) { Vector vel = RandomVector(-64.0f, 64.0f); AngularImpulse angImp = RandomAngularImpulse(-300.0f, 300.0f); vel[2] = 0.0f; pObj->AddVelocity(&vel, &angImp); } if (info.GetDamageType() & DMG_DISSOLVE) { CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating*>(pItem); if (pAnimating) { pAnimating->Dissolve(NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL); } } else { WeaponManager_AddManaged(pItem); } } } else if (FClassnameIs(GetActiveWeapon(), "weapon_smg1")) { CBaseEntity *pItem = DropItem("item_ammo_smg1_grenade", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360)); if (pItem) { IPhysicsObject *pObj = pItem->VPhysicsGetObject(); if (pObj) { Vector vel = RandomVector(-64.0f, 64.0f); AngularImpulse angImp = RandomAngularImpulse(-300.0f, 300.0f); vel[2] = 0.0f; pObj->AddVelocity(&vel, &angImp); } if (info.GetDamageType() & DMG_DISSOLVE) { CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating*>(pItem); if (pAnimating) { pAnimating->Dissolve(NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL); } } else { WeaponManager_AddManaged(pItem); } } } } CHalfLife2 *pHL2GameRules = static_cast<CHalfLife2 *>(g_pGameRules); // Attempt to drop health if ( pHL2GameRules->NPC_ShouldDropHealth( pPlayer ) ) { DropItem( "item_healthvial", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pHL2GameRules->NPC_DroppedHealth(); } if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0) { DropItem("item_shield", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360)); } } BaseClass::Event_Killed( info ); }
//----------------------------------------------------------------------------- // Purpose: // Input : &info - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- void CNPC_CombineS::Event_Killed( const CTakeDamageInfo &info ) { if (!(g_Language.GetInt() == LANGUAGE_GERMAN || UTIL_IsLowViolence()) && info.GetDamageType() & (DMG_BLAST | DMG_CRUSH) && !(info.GetDamageType() & (DMG_DISSOLVE)) && !PlayerHasMegaPhysCannon()) { Vector vecDamageDir = info.GetDamageForce(); SpawnBlood(GetAbsOrigin(), g_vecAttackDir, BloodColor(), info.GetDamage()); DispatchParticleEffect("headshotspray", GetAbsOrigin(), GetAbsAngles(), this); EmitSound("Gore.Headshot"); float flFadeTime = 25.0; CGib::SpawnSpecificGibs(this, 1, 750, 1500, "models/gibs/soldier_head.mdl", flFadeTime); Vector vecRagForce; vecRagForce.x = random->RandomFloat(-400, 400); vecRagForce.y = random->RandomFloat(-400, 400); vecRagForce.z = random->RandomFloat(0, 250); Vector vecRagDmgForce = (vecRagForce + vecDamageDir); CBaseEntity *pLeftArmGib = CreateRagGib("models/gibs/soldier_left_arm.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pLeftArmGib) { color32 color = pLeftArmGib->GetRenderColor(); pLeftArmGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pRightArmGib = CreateRagGib("models/gibs/soldier_right_arm.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pRightArmGib) { color32 color = pRightArmGib->GetRenderColor(); pRightArmGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pTorsoGib = CreateRagGib("models/gibs/soldier_torso.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pTorsoGib) { color32 color = pTorsoGib->GetRenderColor(); pTorsoGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pPelvisGib = CreateRagGib("models/gibs/soldier_pelvis.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pPelvisGib) { color32 color = pPelvisGib->GetRenderColor(); pPelvisGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pLeftLegGib = CreateRagGib("models/gibs/soldier_left_leg.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pLeftLegGib) { color32 color = pLeftLegGib->GetRenderColor(); pLeftLegGib->SetRenderColor(color.r, color.g, color.b, color.a); } CBaseEntity *pRightLegGib = CreateRagGib("models/gibs/soldier_right_leg.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire()); if (pRightLegGib) { color32 color = pRightLegGib->GetRenderColor(); pRightLegGib->SetRenderColor(color.r, color.g, color.b, color.a); } //now add smaller gibs. CGib::SpawnSpecificGibs(this, 3, 750, 1500, "models/gibs/pgib_p3.mdl", flFadeTime); CGib::SpawnSpecificGibs(this, 3, 750, 1500, "models/gibs/pgib_p4.mdl", flFadeTime); Vector forceVector = CalcDamageForceVector(info); // Drop any weapon that I own if (VPhysicsGetObject()) { Vector weaponForce = forceVector * VPhysicsGetObject()->GetInvMass(); Weapon_Drop(m_hActiveWeapon, NULL, &weaponForce); } else { Weapon_Drop(m_hActiveWeapon); } if (info.GetAttacker()->IsPlayer()) { ((CSingleplayRules*)GameRules())->NPCKilled(this, info); } UTIL_Remove(this); SetThink(NULL); return; } // Don't bother if we've been told not to, or the player has a megaphyscannon if ( combine_spawn_health.GetBool() == false || PlayerHasMegaPhysCannon() ) { BaseClass::Event_Killed( info ); return; } CBasePlayer *pPlayer = ToBasePlayer( info.GetAttacker() ); if ( !pPlayer ) { CPropVehicleDriveable *pVehicle = dynamic_cast<CPropVehicleDriveable *>( info.GetAttacker() ) ; if ( pVehicle && pVehicle->GetDriver() && pVehicle->GetDriver()->IsPlayer() ) { pPlayer = assert_cast<CBasePlayer *>( pVehicle->GetDriver() ); } } if ( pPlayer != NULL ) { CHalfLife2 *pHL2GameRules = static_cast<CHalfLife2 *>(g_pGameRules); // Attempt to drop health if ( pHL2GameRules->NPC_ShouldDropHealth( pPlayer ) ) { DropItem( "item_healthvial", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pHL2GameRules->NPC_DroppedHealth(); } if ( HasSpawnFlags( SF_COMBINE_NO_GRENADEDROP ) == false ) { // Attempt to drop a grenade if ( pHL2GameRules->NPC_ShouldDropGrenade( pPlayer ) ) { DropItem( "weapon_frag", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pHL2GameRules->NPC_DroppedGrenade(); } } } BaseClass::Event_Killed( info ); }
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() ); } } }
// make the bleeding more pronounced void CASW_Zombie::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { m_fNoDamageDecal = false; if ( m_takedamage == DAMAGE_NO ) return; CTakeDamageInfo subInfo = info; SetLastHitGroup( ptr->hitgroup ); m_nForceBone = ptr->physicsbone; // save this bone for physics forces Assert( m_nForceBone > -255 && m_nForceBone < 256 ); bool bDebug = showhitlocation.GetBool(); switch ( ptr->hitgroup ) { case HITGROUP_GENERIC: if( bDebug ) DevMsg("Hit Location: Generic\n"); break; // hit gear, react but don't bleed case HITGROUP_GEAR: subInfo.SetDamage( 0.01 ); ptr->hitgroup = HITGROUP_GENERIC; if( bDebug ) DevMsg("Hit Location: Gear\n"); break; case HITGROUP_HEAD: subInfo.ScaleDamage( GetHitgroupDamageMultiplier(ptr->hitgroup, info) ); if( bDebug ) DevMsg("Hit Location: Head\n"); break; case HITGROUP_CHEST: subInfo.ScaleDamage( GetHitgroupDamageMultiplier(ptr->hitgroup, info) ); if( bDebug ) DevMsg("Hit Location: Chest\n"); break; case HITGROUP_STOMACH: subInfo.ScaleDamage( GetHitgroupDamageMultiplier(ptr->hitgroup, info) ); if( bDebug ) DevMsg("Hit Location: Stomach\n"); break; case HITGROUP_LEFTARM: case HITGROUP_RIGHTARM: subInfo.ScaleDamage( GetHitgroupDamageMultiplier(ptr->hitgroup, info) ); if( bDebug ) DevMsg("Hit Location: Left/Right Arm\n"); break ; case HITGROUP_LEFTLEG: case HITGROUP_RIGHTLEG: subInfo.ScaleDamage( GetHitgroupDamageMultiplier(ptr->hitgroup, info) ); if( bDebug ) DevMsg("Hit Location: Left/Right Leg\n"); break; default: if( bDebug ) DevMsg("Hit Location: UNKNOWN\n"); break; } if ( subInfo.GetDamage() >= 1.0 && !(subInfo.GetDamageType() & DMG_SHOCK ) ) { if( !IsPlayer() || ( IsPlayer() && gpGlobals->maxClients > 1 ) ) { // NPC's always bleed. Players only bleed in multiplayer. //SpawnBlood( ptr->endpos, vecDir, BloodColor(), subInfo.GetDamage() );// a little surface blood. //UTIL_ASW_DroneBleed( ptr->endpos, vecDir, 4 ); UTIL_ASW_BloodDrips( GetAbsOrigin()+Vector(0,0,60)+vecDir*3, vecDir, BloodColor(), 5 ); } TraceBleed( subInfo.GetDamage(), vecDir, ptr, subInfo.GetDamageType() ); if ( ptr->hitgroup == HITGROUP_HEAD && m_iHealth - subInfo.GetDamage() > 0 ) { m_fNoDamageDecal = true; } } // Airboat gun will impart major force if it's about to kill him.... if ( info.GetDamageType() & DMG_AIRBOAT ) { if ( subInfo.GetDamage() >= GetHealth() ) { float flMagnitude = subInfo.GetDamageForce().Length(); if ( (flMagnitude != 0.0f) && (flMagnitude < 400.0f * 65.0f) ) { subInfo.ScaleDamageForce( 400.0f * 65.0f / flMagnitude ); } } } if( info.GetInflictor() ) { subInfo.SetInflictor( info.GetInflictor() ); } else { subInfo.SetInflictor( info.GetAttacker() ); } AddMultiDamage( subInfo, this ); }
void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) { pev->model = iStringNull;// make invisible SetThink( &CSqueakGrenade::SUB_Remove ); SetTouch( NULL ); pev->nextthink = gpGlobals->time + 0.1; // since squeak grenades never leave a body behind, clear out their takedamage now. // Squeaks do a bit of radius damage when they pop, and that radius damage will // continue to call this function unless we acknowledge the Squeak's death now. (sjb) pev->takedamage = DAMAGE_NO; // play squeek blast EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM); CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 ); UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 ); if ( !isPenguin ) { if (m_hOwner != NULL) RadiusDamage ( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST, false ); else RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST, false ); } // reset owner so death message happens if (m_hOwner != NULL) pev->owner = m_hOwner->edict(); CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS ); if ( inceptionDepth > 0 ) { Vector spawnPos = pev->origin; CSqueakGrenade *snark1 = ( CSqueakGrenade * ) CBaseEntity::Create( "monster_snark", spawnPos + gpGlobals->v_right * 16 + gpGlobals->v_up * 8, pev->angles, NULL ); snark1->inceptionDepth = inceptionDepth - 1; snark1->pev->velocity = gpGlobals->v_right * ( 160 + RANDOM_LONG( -60, 200 ) ) + gpGlobals->v_up * ( 50 + RANDOM_LONG( -10, 100 ) ); CSqueakGrenade *snark2 = ( CSqueakGrenade * ) CBaseEntity::Create( "monster_snark", spawnPos + gpGlobals->v_right * -16 + gpGlobals->v_up * 8, pev->angles, NULL ); snark2->inceptionDepth = inceptionDepth - 1; snark2->pev->velocity = -gpGlobals->v_right * ( 160 + RANDOM_LONG( -60, 200 ) ) + gpGlobals->v_up * ( 50 + RANDOM_LONG( -10, 100 ) ); } if ( gameplayMods::snarkNuclear.isActive() ) { float damage = gSkillData.plrDmgHandGrenade / 1.8f; RadiusDamage ( pev, pev, damage, CLASS_NONE, DMG_BLAST, false ); MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); if ( UTIL_PointContents ( pev->origin ) != CONTENTS_WATER) { WRITE_SHORT( g_sModelIndexFireball ); } else { WRITE_SHORT( g_sModelIndexWExplosion ); } WRITE_BYTE( ( damage - 50 ) * 0.6f ); // scale * 10 WRITE_BYTE( 15 ); // framerate WRITE_BYTE( TE_EXPLFLAG_NONE ); MESSAGE_END(); } }
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() ); } } }
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() ); } }