//----------------------------------------------------------------------------- // 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 ); }
//----------------------------------------------------------------------------- // Purpose: // Input : &info - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- void CNPC_CombineS::Event_Killed( const CTakeDamageInfo &info ) { // 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 ) { // Elites drop alt-fire ammo, so long as they weren't killed by dissolving. if( IsElite() ) { #ifdef HL2_EPISODIC if ( HasSpawnFlags( SF_COMBINE_NO_AR2DROP ) == false ) #endif { 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 ); } } } } #ifdef HL2_DLL CHalfLife2 *pGameRules = static_cast<CHalfLife2 *>(g_pGameRules); #elif defined(TF_CLASSIC) CTFGameRules *pGameRules = TFGameRules(); #endif // Attempt to drop health if ( pGameRules->NPC_ShouldDropHealth( pPlayer ) ) { DropItem( "item_healthvial", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pGameRules->NPC_DroppedHealth(); } // Don't drop grenades in TF2C, TF2 players don't need that. #ifndef TF_CLASSIC if ( HasSpawnFlags( SF_COMBINE_NO_GRENADEDROP ) == false ) { // Attempt to drop a grenade if ( pGameRules->NPC_ShouldDropGrenade( pPlayer ) ) { DropItem( "weapon_frag", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pGameRules->NPC_DroppedGrenade(); } } #endif } BaseClass::Event_Killed( info ); }
//----------------------------------------------------------------------------- // 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 ); }
int CSDKPlayer::OnTakeDamage_Alive( const CTakeDamageInfo &info ) { // set damage type sustained m_bitsDamageType |= info.GetDamageType(); if ( !CBaseCombatCharacter::OnTakeDamage_Alive( info ) ) return 0; // fire global game event IGameEvent * event = gameeventmanager->CreateEvent( "player_hurt" ); if ( event ) { event->SetInt("userid", GetUserID() ); event->SetInt("health", max(0, m_iHealth) ); event->SetInt("armor", max(0, ArmorValue()) ); if ( info.GetDamageType() & DMG_BLAST ) { event->SetInt( "hitgroup", HITGROUP_GENERIC ); } else { event->SetInt( "hitgroup", LastHitGroup() ); } CBaseEntity * attacker = info.GetAttacker(); const char *weaponName = ""; if ( attacker->IsPlayer() ) { CBasePlayer *player = ToBasePlayer( attacker ); event->SetInt("attacker", player->GetUserID() ); // hurt by other player CBaseEntity *pInflictor = info.GetInflictor(); if ( pInflictor ) { if ( pInflictor == player ) { // If the inflictor is the killer, then it must be their current weapon doing the damage if ( player->GetActiveWeapon() ) { weaponName = player->GetActiveWeapon()->GetClassname(); } } else { weaponName = STRING( pInflictor->m_iClassname ); // it's just that easy } } } else { event->SetInt("attacker", 0 ); // hurt by "world" } if ( strncmp( weaponName, "weapon_", 7 ) == 0 ) { weaponName += 7; } else if( strncmp( weaponName, "grenade", 9 ) == 0 ) //"grenade_projectile" { weaponName = "grenade"; } event->SetString( "weapon", weaponName ); event->SetInt( "priority", 5 ); gameeventmanager->FireEvent( event ); } return 1; }
//========================================================= // Deathnotice. //========================================================= void CHL2MPRules::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info ) { #ifndef CLIENT_DLL // Work out what killed the player, and send a message to all clients about it const char *killer_weapon_name = "world"; // by default, the player is killed by the world int killer_ID = 0; // Find the killer & the scorer CBaseEntity *pInflictor = info.GetInflictor(); CBaseEntity *pKiller = info.GetAttacker(); CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor ); // Custom kill type? if ( info.GetDamageCustom() ) { killer_weapon_name = GetDamageCustomString( info ); if ( pScorer ) { killer_ID = pScorer->GetUserID(); } } else { // Is the killer a client? if ( pScorer ) { killer_ID = pScorer->GetUserID(); if ( pInflictor ) { if ( pInflictor == pScorer ) { // If the inflictor is the killer, then it must be their current weapon doing the damage if ( pScorer->GetActiveWeapon() ) { killer_weapon_name = pScorer->GetActiveWeapon()->GetClassname(); } } else { killer_weapon_name = pInflictor->GetClassname(); // it's just that easy } } } else { killer_weapon_name = pInflictor->GetClassname(); } // strip the NPC_* or weapon_* from the inflictor's classname if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) { killer_weapon_name += 7; } else if ( strncmp( killer_weapon_name, "npc_", 4 ) == 0 ) { killer_weapon_name += 4; } else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) { killer_weapon_name += 5; } else if ( strstr( killer_weapon_name, "physics" ) ) { killer_weapon_name = "physics"; } if ( strcmp( killer_weapon_name, "prop_combine_ball" ) == 0 ) { killer_weapon_name = "combine_ball"; } else if ( strcmp( killer_weapon_name, "grenade_ar2" ) == 0 ) { killer_weapon_name = "smg1_grenade"; } else if ( strcmp( killer_weapon_name, "satchel" ) == 0 || strcmp( killer_weapon_name, "tripmine" ) == 0) { killer_weapon_name = "slam"; } } IGameEvent *event = gameeventmanager->CreateEvent( "player_death" ); if( event ) { event->SetInt("userid", pVictim->GetUserID() ); event->SetInt("attacker", killer_ID ); event->SetString("weapon", killer_weapon_name ); event->SetInt( "priority", 7 ); gameeventmanager->FireEvent( event ); } #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPropAPC2::Event_Killed( const CTakeDamageInfo &info ) { CBasePlayer *pPlayer = m_hPlayer; if ( pPlayer ) { pPlayer->LeaveVehicle(); // Force exit vehicle CBaseEntity *pAPC=this->GetBaseEntity(); CTakeDamageInfo playerinfo; if (info.GetAttacker()==pAPC && info.GetInflictor()==pAPC) { playerinfo.SetAttacker(pPlayer); playerinfo.SetInflictor(pPlayer); playerinfo.SetDamage(10000); playerinfo.SetDamageType(DMG_BLAST); } else { playerinfo.SetAttacker(info.GetAttacker()); playerinfo.SetInflictor(info.GetInflictor()); playerinfo.SetDamage(10000); playerinfo.SetDamageType(DMG_BLAST); } playerinfo.SetDamagePosition( pPlayer->WorldSpaceCenter() ); playerinfo.SetDamageForce( Vector(0,0,-1) ); pPlayer->TakeDamage( playerinfo ); m_hPlayer = NULL; } m_OnDeath.FireOutput( info.GetAttacker(), this ); Vector vecAbsMins, vecAbsMaxs; CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs ); Vector vecNormalizedMins, vecNormalizedMaxs; CollisionProp()->WorldToNormalizedSpace( vecAbsMins, &vecNormalizedMins ); CollisionProp()->WorldToNormalizedSpace( vecAbsMaxs, &vecNormalizedMaxs ); Vector vecAbsPoint; CPASFilter filter( GetAbsOrigin() ); for (int i = 0; i < 3; i++) { CollisionProp()->RandomPointInBounds( vecNormalizedMins, vecNormalizedMaxs, &vecAbsPoint ); te->Explosion( filter, random->RandomFloat( 0.0, 1.0 ), &vecAbsPoint, g_sModelIndexFireball, random->RandomInt( 4, 10 ), random->RandomInt( 8, 15 ), ( i < 2 ) ? TE_EXPLFLAG_NODLIGHTS : TE_EXPLFLAG_NOPARTICLES | TE_EXPLFLAG_NOFIREBALLSMOKE | TE_EXPLFLAG_NODLIGHTS, 100, 0 ); } // TODO: make the gibs spawn in sync with the delayed explosions //int nGibs = random->RandomInt( 1, 4 ); //for ( i = 0; i < nGibs; i++) //{ // // Throw a flaming, smoking chunk. // CGib *pChunk = CREATE_ENTITY( CGib, "gib" ); // pChunk->Spawn( "models/gibs/hgibs.mdl" ); // pChunk->SetBloodColor( DONT_BLEED ); // QAngle vecSpawnAngles; // vecSpawnAngles.Random( -90, 90 ); // pChunk->SetAbsOrigin( vecAbsPoint ); // pChunk->SetAbsAngles( vecSpawnAngles ); // int nGib = random->RandomInt( 0, APC_MAX_CHUNKS - 1 ); // pChunk->Spawn( s_pChunkModelName[nGib] ); // pChunk->SetOwnerEntity( this ); // pChunk->m_lifeTime = random->RandomFloat( 6.0f, 8.0f ); // pChunk->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); // IPhysicsObject *pPhysicsObject = pChunk->VPhysicsInitNormal( SOLID_VPHYSICS, pChunk->GetSolidFlags(), false ); // // // Set the velocity // if ( pPhysicsObject ) // { // pPhysicsObject->EnableMotion( true ); // Vector vecVelocity; // QAngle angles; // angles.x = random->RandomFloat( -20, 20 ); // angles.y = random->RandomFloat( 0, 360 ); // angles.z = 0.0f; // AngleVectors( angles, &vecVelocity ); // // vecVelocity *= random->RandomFloat( 300, 900 ); // vecVelocity += GetAbsVelocity(); // AngularImpulse angImpulse; // angImpulse = RandomAngularImpulse( -180, 180 ); // pChunk->SetAbsVelocity( vecVelocity ); // pPhysicsObject->SetVelocity(&vecVelocity, &angImpulse ); // } // CEntityFlame *pFlame = CEntityFlame::Create( pChunk, false ); // if ( pFlame != NULL ) // { // pFlame->SetLifetime( pChunk->m_lifeTime ); // } // pChunk->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL ); //} UTIL_ScreenShake( vecAbsPoint, 25.0, 150.0, 1.0, 750.0f, SHAKE_START ); //Ignite( 60, false ); //m_lifeState = LIFE_DYING; // Spawn a lesser amount if the player is close /*m_iRocketSalvoLeft = DEATH_VOLLEY_ROCKET_COUNT; m_flRocketTime = gpGlobals->curtime;*/ CreateCorpse(); }
int CSDKPlayer::OnTakeDamage( const CTakeDamageInfo &inputInfo ) { CTakeDamageInfo info = inputInfo; CBaseEntity *pInflictor = info.GetInflictor(); if ( !pInflictor ) return 0; if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER ) return 0; float flArmorBonus = 0.5f; float flArmorRatio = 0.5f; float flDamage = info.GetDamage(); bool bCheckFriendlyFire = false; bool bFriendlyFire = friendlyfire.GetBool(); //Tony; only check teams in teamplay if ( gpGlobals->teamplay ) bCheckFriendlyFire = true; if ( bFriendlyFire || ( bCheckFriendlyFire && pInflictor->GetTeamNumber() != GetTeamNumber() ) || pInflictor == this || info.GetAttacker() == this ) { if ( bFriendlyFire && (info.GetDamageType() & DMG_BLAST) == 0 ) { if ( pInflictor->GetTeamNumber() == GetTeamNumber() && bCheckFriendlyFire) { flDamage *= 0.35; // bullets hurt teammates less } } // keep track of amount of damage last sustained m_lastDamageAmount = flDamage; // Deal with Armour if ( ArmorValue() && !( info.GetDamageType() & (DMG_FALL | DMG_DROWN)) ) { float flNew = flDamage * flArmorRatio; float flArmor = (flDamage - flNew) * flArmorBonus; // Does this use more armor than we have? if (flArmor > ArmorValue() ) { //armorHit = (int)(flArmor); flArmor = ArmorValue(); flArmor *= (1/flArmorBonus); flNew = flDamage - flArmor; SetArmorValue( 0 ); } else { int oldValue = (int)(ArmorValue()); if ( flArmor < 0 ) flArmor = 1; SetArmorValue( oldValue - flArmor ); //armorHit = oldValue - (int)(pev->armorvalue); } flDamage = flNew; info.SetDamage( flDamage ); } // round damage to integer info.SetDamage( (int)flDamage ); if ( info.GetDamage() <= 0 ) return 0; CSingleUserRecipientFilter user( this ); user.MakeReliable(); UserMessageBegin( user, "Damage" ); WRITE_BYTE( (int)info.GetDamage() ); WRITE_VEC3COORD( info.GetInflictor()->WorldSpaceCenter() ); MessageEnd(); // Do special explosion damage effect if ( info.GetDamageType() & DMG_BLAST ) { OnDamagedByExplosion( info ); } gamestats->Event_PlayerDamage( this, info ); return CBaseCombatCharacter::OnTakeDamage( info ); } else { return 0; } }
// 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 ); }
//========================================================= // Deathnotice. //========================================================= void CMultiplayRules::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info ) { // Work out what killed the player, and send a message to all clients about it const char *killer_weapon_name = "world"; // by default, the player is killed by the world int killer_ID = 0; // Find the killer & the scorer CBaseEntity *pInflictor = info.GetInflictor(); CBaseEntity *pKiller = info.GetAttacker(); CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor ); // Custom kill type? if ( info.GetCustomKill() ) { killer_weapon_name = GetCustomKillString( info ); if ( pScorer ) { killer_ID = pScorer->GetUserID(); } } else { // Is the killer a client? if ( pScorer ) { killer_ID = pScorer->GetUserID(); if ( pInflictor ) { if ( pInflictor == pScorer ) { // If the inflictor is the killer, then it must be their current weapon doing the damage if ( pScorer->GetActiveWeapon() ) { killer_weapon_name = pScorer->GetActiveWeapon()->GetDeathNoticeName(); } } else { killer_weapon_name = STRING( pInflictor->m_iClassname ); // it's just that easy } } } else { killer_weapon_name = STRING( pInflictor->m_iClassname ); } // strip the NPC_* or weapon_* from the inflictor's classname if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) { killer_weapon_name += 7; } else if ( strncmp( killer_weapon_name, "NPC_", 8 ) == 0 ) { killer_weapon_name += 8; } else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) { killer_weapon_name += 5; } } IGameEvent * event = gameeventmanager->CreateEvent( "player_death" ); if ( event ) { event->SetInt("userid", pVictim->GetUserID() ); event->SetInt("attacker", killer_ID ); event->SetInt("priority", 7 ); // HLTV event priority, not transmitted gameeventmanager->FireEvent( event ); } }
Vector CASW_Simple_Alien::CalcDeathForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if ( info.GetDamageForce() != vec3_origin || (g_pGameRules->Damage_NoPhysicsForce(info.GetDamageType()))) { if( info.GetDamageType() & DMG_BLAST ) { float scale = random->RandomFloat( 0.85, 1.15 ); Vector force = info.GetDamageForce(); force.x *= scale; force.y *= scale; // Try to always exaggerate the upward force because we've got pretty harsh gravity force.z *= (force.z > 0) ? 1.15 : scale; return force; } return info.GetDamageForce(); } CBaseEntity *pForce = info.GetInflictor(); if ( !pForce ) { pForce = info.GetAttacker(); } if ( pForce ) { // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage float forceScale = info.GetDamage() * 75 * 4; Vector forceVector; // If the damage is a blast, point the force vector higher than usual, this gives // the ragdolls a bodacious "really got blowed up" look. if( info.GetDamageType() & DMG_BLAST ) { // exaggerate the force from explosions a little (37.5%) forceVector = (GetLocalOrigin() + Vector(0, 0, WorldAlignSize().z) ) - pForce->GetLocalOrigin(); VectorNormalize(forceVector); forceVector *= 1.375f; } else { // taking damage from self? Take a little random force, but still try to collapse on the spot. if ( this == pForce ) { forceVector.x = random->RandomFloat( -1.0f, 1.0f ); forceVector.y = random->RandomFloat( -1.0f, 1.0f ); forceVector.z = 0.0; forceScale = random->RandomFloat( 1000.0f, 2000.0f ); } else { // UNDONE: Collision forces are baked in to CTakeDamageInfo now // UNDONE: Is this MOVETYPE_VPHYSICS code still necessary? if ( pForce->GetMoveType() == MOVETYPE_VPHYSICS ) { // killed by a physics object IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( !pPhysics ) { pPhysics = pForce->VPhysicsGetObject(); } pPhysics->GetVelocity( &forceVector, NULL ); forceScale = pPhysics->GetMass(); } else { forceVector = GetLocalOrigin() - pForce->GetLocalOrigin(); VectorNormalize(forceVector); } } } return forceVector * forceScale; } return vec3_origin; }
void CASW_Alien::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { #ifdef GAME_DLL m_fNoDamageDecal = false; if ( m_takedamage == DAMAGE_NO ) return; #endif CTakeDamageInfo subInfo = info; #ifdef GAME_DLL SetLastHitGroup( ptr->hitgroup ); m_nForceBone = ptr->physicsbone; // save this bone for physics forces #endif Assert( m_nForceBone > -255 && m_nForceBone < 256 ); // mining laser does reduced damage if ( info.GetDamageType() & DMG_ENERGYBEAM ) { subInfo.ScaleDamage( asw_alien_mining_laser_damage_scale.GetFloat() ); } if ( subInfo.GetDamage() >= 1.0 && !(subInfo.GetDamageType() & DMG_SHOCK ) && !( subInfo.GetDamageType() & DMG_BURN ) ) { #ifdef GAME_DLL Bleed( subInfo, ptr->endpos + m_LagCompensation.GetLagCompensationOffset(), vecDir, ptr ); if ( ptr->hitgroup == HITGROUP_HEAD && m_iHealth - subInfo.GetDamage() > 0 ) { m_fNoDamageDecal = true; } #else Bleed( subInfo, ptr->endpos, vecDir, ptr ); //OnHurt(); #endif } if( !info.GetInflictor() ) { subInfo.SetInflictor( info.GetAttacker() ); } AddMultiDamage( subInfo, this ); #ifdef GAME_DLL #else CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>( subInfo.GetAttacker() ); CASW_Player *pPlayerAttacker = NULL; if ( pMarine ) { pPlayerAttacker = pMarine->GetCommander(); } IGameEvent * event = gameeventmanager->CreateEvent( "alien_hurt" ); if ( event ) { event->SetInt( "attacker", ( pPlayerAttacker ? pPlayerAttacker->GetUserID() : 0 ) ); event->SetInt( "entindex", entindex() ); event->SetInt( "amount", subInfo.GetDamage() ); gameeventmanager->FireEventClientSide( event ); } UTIL_ASW_ClientFloatingDamageNumber( subInfo ); #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPropAPC::Event_Killed( const CTakeDamageInfo &info ) { m_OnDeath.FireOutput( info.GetAttacker(), this ); Vector vecAbsMins, vecAbsMaxs; CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs ); Vector vecNormalizedMins, vecNormalizedMaxs; CollisionProp()->WorldToNormalizedSpace( vecAbsMins, &vecNormalizedMins ); CollisionProp()->WorldToNormalizedSpace( vecAbsMaxs, &vecNormalizedMaxs ); Vector vecAbsPoint; CPASFilter filter( GetAbsOrigin() ); for (int i = 0; i < 5; i++) { CollisionProp()->RandomPointInBounds( vecNormalizedMins, vecNormalizedMaxs, &vecAbsPoint ); te->Explosion( filter, random->RandomFloat( 0.0, 1.0 ), &vecAbsPoint, g_sModelIndexFireball, random->RandomInt( 4, 10 ), random->RandomInt( 8, 15 ), ( i < 2 ) ? TE_EXPLFLAG_NODLIGHTS : TE_EXPLFLAG_NOPARTICLES | TE_EXPLFLAG_NOFIREBALLSMOKE | TE_EXPLFLAG_NODLIGHTS, 100, 0 ); } // TODO: make the gibs spawn in sync with the delayed explosions int nGibs = random->RandomInt( 1, 4 ); for ( int i = 0; i < nGibs; i++) { // Throw a flaming, smoking chunk. CGib *pChunk = CREATE_ENTITY( CGib, "gib" ); pChunk->Spawn( "models/gibs/hgibs.mdl" ); pChunk->SetBloodColor( DONT_BLEED ); QAngle vecSpawnAngles; vecSpawnAngles.Random( -90, 90 ); pChunk->SetAbsOrigin( vecAbsPoint ); pChunk->SetAbsAngles( vecSpawnAngles ); int nGib = random->RandomInt( 0, APC_MAX_CHUNKS - 1 ); pChunk->Spawn( s_pChunkModelName[nGib] ); pChunk->SetOwnerEntity( this ); pChunk->m_lifeTime = random->RandomFloat( 6.0f, 8.0f ); pChunk->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); IPhysicsObject *pPhysicsObject = pChunk->VPhysicsInitNormal( SOLID_VPHYSICS, pChunk->GetSolidFlags(), false ); // Set the velocity if ( pPhysicsObject ) { pPhysicsObject->EnableMotion( true ); Vector vecVelocity; QAngle angles; angles.x = random->RandomFloat( -20, 20 ); angles.y = random->RandomFloat( 0, 360 ); angles.z = 0.0f; AngleVectors( angles, &vecVelocity ); vecVelocity *= random->RandomFloat( 300, 900 ); vecVelocity += GetAbsVelocity(); AngularImpulse angImpulse; angImpulse = RandomAngularImpulse( -180, 180 ); pChunk->SetAbsVelocity( vecVelocity ); pPhysicsObject->SetVelocity(&vecVelocity, &angImpulse ); } CEntityFlame *pFlame = CEntityFlame::Create( pChunk, false ); if ( pFlame != NULL ) { pFlame->SetLifetime( pChunk->m_lifeTime ); } } UTIL_ScreenShake( vecAbsPoint, 25.0, 150.0, 1.0, 750.0f, SHAKE_START ); if( hl2_episodic.GetBool() ) { // EP1 perf hit Ignite( 6, false ); } else { Ignite( 60, false ); } m_lifeState = LIFE_DYING; // Spawn a lesser amount if the player is close m_iRocketSalvoLeft = DEATH_VOLLEY_ROCKET_COUNT; m_flRocketTime = gpGlobals->curtime; }
void CGEStats::Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info ) { //Make sure there is a player taking the damage if( !pBasePlayer ) return; int iVictim = FindPlayer( pBasePlayer ); CBasePlayer* pAttacker = static_cast<CBasePlayer*>(info.GetAttacker()); if( !pAttacker->IsPlayer() ) return; int iAttacker = FindPlayer( pAttacker ); // We hurt ourselves... if ( iAttacker == iVictim ) { m_pPlayerStats[iVictim]->AddStat( GE_AWARD_PROFESSIONAL, -2); m_pPlayerStats[iVictim]->AddStat( GE_AWARD_LEMMING, 1 ); return; } // Add the inflicted damage to our Most Deadly stat m_pPlayerStats[iAttacker]->AddStat( GE_AWARD_DEADLY, info.GetDamage() ); // Add to the victim's mostly harmless award 1/2 the damage m_pPlayerStats[iVictim]->AddStat( GE_AWARD_MOSTLYHARMLESS, info.GetDamage() / 2 ); // See where this attack hit and then apply appropriate marksmanship points int points = 0; switch ( pBasePlayer->LastHitGroup() ) { case HITGROUP_HEAD: points = 5; break; case HITGROUP_CHEST: case HITGROUP_STOMACH: points = 3; break; case HITGROUP_LEFTARM: case HITGROUP_RIGHTARM: case HITGROUP_LEFTLEG: case HITGROUP_RIGHTLEG: points = 1; break; } m_pPlayerStats[iAttacker]->AddStat( GE_AWARD_MARKSMANSHIP, points ); // test if its fall damage if( !info.GetInflictor() ) { m_pPlayerStats[iVictim]->AddStat( GE_AWARD_PROFESSIONAL, -2); return; } // Find out what weapons we are using CGEWeapon *pVicWeapon = static_cast<CGEWeapon*>(pBasePlayer->GetActiveWeapon()); CGEWeapon *pWeapon = NULL; if ( info.GetInflictor() == pAttacker ) pWeapon = static_cast<CGEWeapon*>(pAttacker->GetActiveWeapon()); else pWeapon = dynamic_cast<CGEWeapon*>(info.GetInflictor()); // If the victim reports no weapon, or our victim wasn't killed by a GEWeapon, then break if ( !pWeapon || !pVicWeapon ) return; // Don't give honor to mine kills as it doesn't make a difference if ( pWeapon->GetWeaponID() < WEAPON_TIMEDMINE || pWeapon->GetWeaponID() > WEAPON_GRENADE ) { // Define variables to find honor Vector vecVic, vecToAtt, right; // Get the victim's forward normal, their position, and the attacker's position pBasePlayer->EyeVectors( &vecVic, &right ); vecVic.NormalizeInPlace(); // Use vector subtration to find a vector to the attacker FROM the victim vecToAtt = pAttacker->EyePosition() - pBasePlayer->EyePosition(); vecToAtt.NormalizeInPlace(); // Find the angle between the two vectors float front = DotProduct(vecToAtt, vecVic); float side = DotProduct(vecToAtt, right); float xpos = 360.0f * -side; float ypos = 360.0f * -front; // Get the rotation (yaw) float ang = abs( atan2(xpos, ypos) ); float scale; if ( ang > 2.10f ) { scale = RemapValClamped( ang, 2.10f, 3.14f, 0.2f, 1.0f ); m_pPlayerStats[iAttacker]->AddStat( GE_AWARD_HONORABLE, 10*scale ); } else if ( ang < 1.05f ) { scale = RemapValClamped( ang, 0.0f, 1.05f, 0.2f, 1.0f ); m_pPlayerStats[iAttacker]->AddStat( GE_AWARD_DISHONORABLE, 10*scale ); } } //Attacker using slappers, Victim not if( pWeapon->GetWeaponID() == WEAPON_SLAPPERS && pVicWeapon->GetWeaponID() != WEAPON_SLAPPERS ) { m_pPlayerStats[iAttacker]->AddStat(GE_AWARD_DEADLY, 10); m_pPlayerStats[iAttacker]->AddStat(GE_AWARD_HONORABLE, 10); } //Victim using slappers, Attacker not if( pWeapon->GetWeaponID() != WEAPON_SLAPPERS && pVicWeapon->GetWeaponID() == WEAPON_SLAPPERS ) { m_pPlayerStats[iAttacker]->AddStat(GE_AWARD_DISHONORABLE, 10); m_pPlayerStats[iAttacker]->AddStat(GE_AWARD_PROFESSIONAL, -5); } BaseClass::Event_PlayerDamage( pBasePlayer, info ); }
int CSDKPlayer::OnTakeDamage_Alive( const CTakeDamageInfo &info ) { // set damage type sustained m_bitsDamageType |= info.GetDamageType(); if ( !CBaseCombatCharacter::OnTakeDamage_Alive( info ) ) return 0; CBaseEntity * attacker = info.GetAttacker(); if ( !attacker ) return 0; Vector vecDir = vec3_origin; if ( info.GetInflictor() ) { vecDir = info.GetInflictor()->WorldSpaceCenter() - Vector ( 0, 0, 10 ) - WorldSpaceCenter(); VectorNormalize( vecDir ); } if ( info.GetInflictor() && (GetMoveType() == MOVETYPE_WALK) && ( !attacker->IsSolidFlagSet(FSOLID_TRIGGER)) ) { Vector force = vecDir;// * -DamageForce( WorldAlignSize(), info.GetBaseDamage() ); if ( force.z > 250.0f ) { force.z = 250.0f; } ApplyAbsVelocityImpulse( force ); } // Burnt if ( info.GetDamageType() & DMG_BURN ) { EmitSound( "Player.BurnPain" ); } // fire global game event IGameEvent * event = gameeventmanager->CreateEvent( "player_hurt" ); if ( event ) { event->SetInt("userid", GetUserID() ); event->SetInt("health", MAX(0, m_iHealth) ); event->SetInt("priority", 5 ); // HLTV event priority, not transmitted if ( attacker->IsPlayer() ) { CBasePlayer *player = ToBasePlayer( attacker ); event->SetInt("attacker", player->GetUserID() ); // hurt by other player } else { event->SetInt("attacker", 0 ); // hurt by "world" } gameeventmanager->FireEvent( event ); } // Insert a combat sound so that nearby NPCs hear battle if ( attacker->IsNPC() ) { CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 512, 0.5, this ); } return 1; }
//------------------------------------------------------------------------------ // Purpose: Accepts damage and breaks if health drops below zero. //------------------------------------------------------------------------------ void CBreakableSurface::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ) { //============================================================================= // HPE_BEGIN: // [dwenger] Window break stat tracking //============================================================================= // Make sure this pane has not already been shattered bool bWasBroken = m_bIsBroken; //============================================================================= // HPE_END //============================================================================= // Decrease health m_iHealth -= info.GetDamage(); m_OnHealthChanged.Set( m_iHealth, info.GetAttacker(), this ); // If I'm not broken yet, break me if (!m_bIsBroken ) { Vector vSurfDir = ptr->endpos - ptr->startpos; Die( info.GetAttacker(), vSurfDir ); } if (info.GetDamageType() & (DMG_BULLET | DMG_CLUB)) { // Figure out which panel has taken the damage and break it float flWidth,flHeight; PanePos(ptr->endpos,&flWidth,&flHeight); int nWidth = flWidth; int nHeight = flHeight; if ( ShatterPane(nWidth, nHeight,vecDir*500,ptr->endpos) ) { //============================================================================= // HPE_BEGIN: // [dwenger] Window break stat tracking //============================================================================= CBasePlayer* pAttacker = ToBasePlayer(info.GetAttacker()); if ( ( pAttacker ) && ( !bWasBroken ) ) { gamestats->Event_WindowShattered( pAttacker ); } //============================================================================= // HPE_END //============================================================================= // Do an impact hit CEffectData data; data.m_vNormal = ptr->plane.normal; data.m_vOrigin = ptr->endpos; CPASFilter filter( data.m_vOrigin ); // client cannot trace against triggers filter.SetIgnorePredictionCull( true ); te->DispatchEffect( filter, 0.0, data.m_vOrigin, "GlassImpact", data ); } if (m_nSurfaceType == SHATTERSURFACE_GLASS) { // Break nearby panes if damages was near pane edge float flWRem = flWidth - nWidth; float flHRem = flHeight - nHeight; if (flWRem > 0.8 && nWidth != m_nNumWide-1) { ShatterPane(nWidth+1, nHeight,vecDir*500,ptr->endpos); } else if (flWRem < 0.2 && nWidth != 0) { ShatterPane(nWidth-1, nHeight,vecDir*500,ptr->endpos); } if (flHRem > 0.8 && nHeight != m_nNumHigh-1) { ShatterPane(nWidth, nHeight+1,vecDir*500,ptr->endpos); } else if (flHRem < 0.2 && nHeight != 0) { ShatterPane(nWidth, nHeight-1,vecDir*500,ptr->endpos); } // Occasionally break the pane above me if (random->RandomInt(0,1)==0) { ShatterPane(nWidth, nHeight+1,vecDir*1000,ptr->endpos); // Occasionally break the pane above that if (random->RandomInt(0,1)==0) { ShatterPane(nWidth, nHeight+2,vecDir*1000,ptr->endpos); } } } } else if (info.GetDamageType() & (DMG_SONIC | DMG_BLAST)) { // ---------------------------------------- // If it's tile blow out nearby tiles // ---------------------------------------- if (m_nSurfaceType == SHATTERSURFACE_TILE) { // Figure out which panel has taken the damage and break it float flWidth,flHeight; if (info.GetAttacker()) { PanePos(info.GetAttacker()->GetAbsOrigin(),&flWidth,&flHeight); } else { PanePos(ptr->endpos,&flWidth,&flHeight); } int nWidth = flWidth; int nHeight = flHeight; // Blow out a roughly circular patch of tile with some randomness for (int width =nWidth-4;width<nWidth+4;width++) { for (int height =nHeight-4;height<nHeight+4;height++) { if ((abs(nWidth-width)+abs(nHeight-height))<random->RandomInt(2,5)) { ShatterPane(width, height,vecDir*500,ptr->endpos); } } } } // ---------------------------------------- // If it's glass blow out the whole window // ---------------------------------------- else { //============================================================================= // HPE_BEGIN: // [pfreese] Window break stat tracking //============================================================================= CBasePlayer* pAttacker = ToBasePlayer(info.GetAttacker()); if ( ( pAttacker ) && ( !bWasBroken ) ) { gamestats->Event_WindowShattered( pAttacker ); } //============================================================================= // HPE_END //============================================================================= float flDot = DotProduct(m_vNormal,vecDir); #ifdef CSTRIKE_DLL float damageMultiplier = info.GetDamage(); #else float damageMultiplier = 1.0f; #endif Vector vBlastDir; if (flDot > 0) { vBlastDir = damageMultiplier * 3000 * m_vNormal; } else { vBlastDir = damageMultiplier * -3000 * m_vNormal; } // Has the window already been destroyed? if (m_nNumBrokenPanes >= m_nNumWide*m_nNumHigh) { return; } // --------------------------------------------------------------- // If less than 10% of my panels have been broken, blow me // up in one large glass shatter // --------------------------------------------------------------- else if ( m_nNumBrokenPanes < 0.1*(m_nNumWide*m_nNumHigh)) { QAngle vAngles; VectorAngles(-1*m_vNormal,vAngles); CreateShards(m_vCorner, vAngles,vBlastDir, ptr->endpos, m_nNumWide*m_flPanelWidth, m_nNumHigh*m_flPanelHeight, WINDOW_LARGE_SHARD_SIZE); } // --------------------------------------------------------------- // Otherwise break in the longest vertical strips possible // (to cut down on the network bandwidth) // --------------------------------------------------------------- else { QAngle vAngles; VectorAngles(-1*m_vNormal,vAngles); Vector vWidthDir,vHeightDir; AngleVectors(vAngles,NULL,&vWidthDir,&vHeightDir); for (int width=0;width<m_nNumWide;width++) { int height; int nHCount = 0; for ( height=0;height<m_nNumHigh;height++) { // Keep count of how many panes if (!IsBroken(width,height)) { nHCount++; } // Shatter the strip and start counting again else if (nHCount > 0) { Vector vBreakPos = m_vCorner + (width*vWidthDir*m_flPanelWidth) + ((height-nHCount)*vHeightDir*m_flPanelHeight); CreateShards(vBreakPos, vAngles, vBlastDir, ptr->endpos, m_flPanelWidth, nHCount*m_flPanelHeight, WINDOW_LARGE_SHARD_SIZE); nHCount = 0; } } if (nHCount) { Vector vBreakPos = m_vCorner + (width*vWidthDir*m_flPanelWidth) + ((height-nHCount)*vHeightDir*m_flPanelHeight); CreateShards(vBreakPos, vAngles, vBlastDir, ptr->endpos, m_flPanelWidth,nHCount*m_flPanelHeight, WINDOW_LARGE_SHARD_SIZE); } } } BreakAllPanes(); } } }
void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) { const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX); CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; #ifdef HL2_DLL if( bInWater ) { // Only muffle the explosion if deeper than 2 feet in water. if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24)) & MASK_WATER) ) { bInWater = false; } } #endif // HL2_DLL vecSrc.z += 1;// in case grenade is lying on the ground float flHalfRadiusSqr = Square( flRadius / 2.0f ); // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) { // This value is used to scale damage when the explosion is blocked by some other object. float flBlockedDamagePercent = 0.0f; if ( pEntity == pEntityIgnore ) continue; if ( pEntity->m_takedamage == DAMAGE_NO ) continue; // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // Check that the explosion can 'see' this entity. vecSpot = pEntity->BodyTarget( vecSrc, false ); UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( old_radius_damage.GetBool() ) { if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) continue; } else { if ( tr.fraction != 1.0 ) { if ( IsExplosionTraceBlocked(&tr) ) { if( ShouldUseRobustRadiusDamage( pEntity ) ) { if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr ) { // Only use robust model on a target within one-half of the explosion's radius. continue; } Vector vecToTarget = vecSpot - tr.endpos; VectorNormalize( vecToTarget ); // We're going to deflect the blast along the surface that // interrupted a trace from explosion to this target. Vector vecUp, vecDeflect; CrossProduct( vecToTarget, tr.plane.normal, vecUp ); CrossProduct( tr.plane.normal, vecUp, vecDeflect ); VectorNormalize( vecDeflect ); // Trace along the surface that intercepted the blast... UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 ); // ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated. UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 ); if( tr.fraction != 1.0 && tr.DidHitWorld() ) { // Still can't reach the target. continue; } // else fall through } else { continue; } } // UNDONE: Probably shouldn't let children block parents either? Or maybe those guys should set their owner if they want this behavior? // HL2 - Dissolve damage is not reduced by interposing non-world objects if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity ) { // Some entity was hit by the trace, meaning the explosion does not have clear // line of sight to the entity that it's trying to hurt. If the world is also // blocking, we do no damage. CBaseEntity *pBlockingEntity = tr.m_pEnt; //Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() ); UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( tr.fraction != 1.0 ) { continue; } // Now, if the interposing object is physics, block some explosion force based on its mass. if( pBlockingEntity->VPhysicsGetObject() ) { const float MASS_ABSORB_ALL_DAMAGE = 350.0f; float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass(); float scale = flMass / MASS_ABSORB_ALL_DAMAGE; // Absorbed all the damage. if( scale >= 1.0f ) { continue; } ASSERT( scale > 0.0f ); flBlockedDamagePercent = scale; //Msg(" Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f); } else { // Some object that's not the world and not physics. Generically block 25% damage flBlockedDamagePercent = 0.25f; } } } } // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage <= 0 ) { continue; } // the explosion can 'see' this entity, so hurt them! if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } CTakeDamageInfo adjustedInfo = info; //Msg("%s: Blocked damage: %f percent (in:%f out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); // Now make a consideration for skill level! if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() ) { // An explosion set off by the player is harming an NPC. Adjust damage accordingly. adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel(); } Vector dir = vecSpot - vecSrc; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc ); } } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt ) { ClearMultiDamage( ); pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); ApplyMultiDamage(); } else { pEntity->TakeDamage( adjustedInfo ); } // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); #if defined( GAME_DLL ) if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) ) { // This is a total hack!!! bool bIsPrimary = true; CBasePlayer *player = ToBasePlayer( info.GetAttacker() ); CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) ) { bIsPrimary = false; } gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info ); } #endif } }
//----------------------------------------------------------------------------- // Purpose: Intercept damage and decide whether or not we want to trigger // Input : &info - //----------------------------------------------------------------------------- int CWeaponStriderBuster::OnTakeDamage( const CTakeDamageInfo &info ) { // If we're attached, any damage from the player makes us trigger CBaseEntity *pInflictor = info.GetInflictor(); CBaseEntity *pAttacker = info.GetAttacker(); bool bInflictorIsPlayer = ( pInflictor != NULL && pInflictor->IsPlayer() ); bool bAttackerIsPlayer = ( pAttacker != NULL && pAttacker->IsPlayer() ); if ( GetParent() && GetParent()->ClassMatches( g_iszVehicle ) ) { return 0; } // Only take damage from a player, for the moment if ( striderbuster_allow_all_damage.GetBool() || ( IsAttachedToStrider() && ( bAttackerIsPlayer || bInflictorIsPlayer ) ) ) { Detonate(); return 0; } if ( pAttacker && ( pAttacker->Classify() == CLASS_COMBINE || pAttacker->Classify() == CLASS_COMBINE_HUNTER ) ) { if ( VPhysicsGetObject() && !VPhysicsGetObject()->IsMoveable() ) { return 0; } } // Hunters are able to destroy strider busters if ( hunter_hate_held_striderbusters.GetBool() || hunter_hate_thrown_striderbusters.GetBool() || hunter_hate_attached_striderbusters.GetBool() ) { if ( ( GetHealth() > 0 ) && ( pInflictor != NULL ) && FClassnameIs( pInflictor, "hunter_flechette" ) ) { // // Flechette impacts don't hurt the striderbuster unless it's attached to a strider, // but the explosions always do. This is so that held or thrown striderbusters fly // awry because of the flechette, but attached striderbusters break instantly to make // the hunters more effective at defending the strider. // if ( IsAttachedToStrider() || !( info.GetDamageType() & DMG_NEVERGIB ) ) { if( striderbuster_die_detach.GetBool() && IsAttachedToStrider() ) { // Make the buster fall off and break. m_takedamage = DAMAGE_NO; CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(GetOwnerEntity()); Assert( pStrider != NULL ); pStrider->StriderBusterDetached( this ); DestroyConstraint(); // Amplify some lateral force. Vector vecForce = info.GetDamageForce(); vecForce.z = 0.0f; VPhysicsGetObject()->ApplyForceCenter( vecForce * 5.0f ); SetContextThink( NULL, gpGlobals->curtime, s_pBusterPingThinkContext ); SetThink( &CWeaponStriderBuster::BusterDetachThink ); SetNextThink( gpGlobals->curtime ); m_iBusterFlags |= STRIDERBUSTER_FLAG_KNOCKED_OFF_STRIDER; return 0; } else { // Destroy the buster in place // Make sure they know it blew up prematurely. EmitSound( "Weapon_StriderBuster.Dud_Detonate" ); DispatchParticleEffect( "striderbuster_break_flechette", GetAbsOrigin(), GetAbsAngles() ); SetHealth( 0 ); Shatter( info.GetAttacker() ); return 0; } } if ( info.GetDamage() < 5 ) { bool bFirst = ( m_CarryAngles.x == 45 && m_CarryAngles.y == 0 && m_CarryAngles.z == 0); float sinTime = sin( gpGlobals->curtime ); bool bSubtractX = ( bFirst ) ? ( sinTime < 0 ) : ( m_CarryAngles.x < 45 ); m_CarryAngles.x += ( 10.0 + 10.0 * fabsf( sinTime ) + random->RandomFloat( -2.5, 2.5 ) + random->RandomFloat( -2.5, 2.5 ) ) * ( ( bSubtractX ) ? -1.0 : 1.0 ); m_CarryAngles.y = 15 * ( sin( gpGlobals->curtime ) + cos( gpGlobals->curtime * 0.5 ) ) * .5 + random->RandomFloat( -15, 15 ); m_CarryAngles.z = 7.5 * ( sin( gpGlobals->curtime ) + sin( gpGlobals->curtime * 2.0 ) ) * .5 + random->RandomFloat( -7.5, 7.5 ); } return 1; } } // Allow crushing damage if ( info.GetDamageType() & DMG_CRUSH ) return BaseClass::OnTakeDamage( info ); return 0; }
//----------------------------------------------------------------------------- // Purpose: // Input : &info - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- void CTDP_NPC_CombineS::Event_Killed( const CTakeDamageInfo &info ) { // 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 != NULL ) { // Elites drop alt-fire ammo, so long as they weren't killed by dissolving. if( IsElite() ) { 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 ); } } } } //CTDPGameRules *pTDPGameRules = static_cast<CTDPGameRules *>(g_pGameRules); // Attempt to drop health /*if ( pTDPGameRules->NPC_ShouldDropHealth( pPlayer ) ) { DropItem( "item_healthvial", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pTDPGameRules->NPC_DroppedHealth(); }*/ // Attempt to drop a grenade /*if ( pTDPGameRules->NPC_ShouldDropGrenade( pPlayer ) ) { DropItem( "weapon_frag", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pTDPGameRules->NPC_DroppedGrenade(); }*/ } BaseClass::Event_Killed( info ); }