//--------------------------------------------------------- //--------------------------------------------------------- int CZombie::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ) { #ifndef HL2_EPISODIC if ( inputInfo.GetDamageType() & DMG_BUCKSHOT ) { if( inputInfo.GetDamage() > (m_iMaxHealth/3) ) { // Always flinch if damaged a lot by buckshot, even if not shot in the head. // The reason for making sure we did at least 1/3rd of the zombie's max health // is so the zombie doesn't flinch every time the odd shotgun pellet hits them, // and so the maximum number of times you'll see a zombie flinch like this is 2.(sjb) AddGesture( ACT_GESTURE_FLINCH_HEAD ); } } #endif // HL2_EPISODIC return BaseClass::OnTakeDamage_Alive( inputInfo ); }
//----------------------------------------------------------------------------- // Purpose: // Input : &inputInfo - // Output : int //----------------------------------------------------------------------------- int CNPC_PoisonZombie::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ) { // // Calculate what percentage of the creature's max health // this amount of damage represents (clips at 1.0). // float flDamagePercent = min( 1, inputInfo.GetDamage() / m_iMaxHealth ); // // Throw one crab for every 20% damage we take. // if ( flDamagePercent >= 0.2 ) { m_flNextCrabThrowTime = gpGlobals->curtime; } return BaseClass::OnTakeDamage_Alive( inputInfo ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CPropAPC::OnTakeDamage( const CTakeDamageInfo &info ) { if ( m_iHealth == 0 ) return 0; m_OnDamaged.FireOutput( info.GetAttacker(), this ); if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() ) { m_OnDamagedByPlayer.FireOutput( info.GetAttacker(), this ); } CTakeDamageInfo dmgInfo = info; if ( dmgInfo.GetDamageType() & (DMG_BLAST | DMG_AIRBOAT) ) { int nPrevHealth = GetHealth(); m_iHealth -= dmgInfo.GetDamage(); if ( m_iHealth <= 0 ) { m_iHealth = 0; Event_Killed( dmgInfo ); return 0; } // Chain // BaseClass::OnTakeDamage( dmgInfo ); // Spawn damage effects if ( nPrevHealth != GetHealth() ) { if ( ShouldTriggerDamageEffect( nPrevHealth, MAX_SMOKE_TRAILS ) ) { AddSmokeTrail( dmgInfo.GetDamagePosition() ); } if ( ShouldTriggerDamageEffect( nPrevHealth, MAX_EXPLOSIONS ) ) { ExplodeAndThrowChunk( dmgInfo.GetDamagePosition() ); } } } return 1; }
void CZombie::OnTakeDamage( const CTakeDamageInfo& info ) { CTakeDamageInfo newInfo = info; // Take 30% damage from bullets if ( newInfo.GetDamageTypes() == DMG_BULLET ) { Vector vecDir = GetAbsOrigin() - ( newInfo.GetInflictor()->pev->absmin + newInfo.GetInflictor()->pev->absmax) * 0.5; vecDir = vecDir.Normalize(); float flForce = DamageForce( newInfo.GetDamage() ); pev->velocity = pev->velocity + vecDir * flForce; newInfo.GetMutableDamage() *= 0.3; } // HACK HACK -- until we fix this. if ( IsAlive() ) PainSound(); CBaseMonster::OnTakeDamage( newInfo ); }
//----------------------------------------------------------------------------- // Purpose: // Input : &info - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CTDP_NPC_CombineS::IsHeavyDamage( const CTakeDamageInfo &info ) { // Combine considers AR2 fire to be heavy damage if ( info.GetAmmoType() == GetAmmoDef()->Index("AR2") ) return true; // 357 rounds are heavy damage if ( info.GetAmmoType() == GetAmmoDef()->Index("357") ) return true; // Shotgun blasts where at least half the pellets hit me are heavy damage if ( info.GetDamageType() & DMG_BUCKSHOT ) { int iHalfMax = sk_plr_dmg_buckshot.GetFloat() * sk_plr_num_shotgun_pellets.GetInt() * 0.5; if ( info.GetDamage() >= iHalfMax ) return true; } return BaseClass::IsHeavyDamage( info ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CPropVehicleChoreoGeneric::OnTakeDamage( const CTakeDamageInfo &inputInfo ) { CTakeDamageInfo info = inputInfo; info.ScaleDamage( 25 ); // reset the damage info.SetDamage( inputInfo.GetDamage() ); // Check to do damage to prisoner if ( m_hPlayer != NULL ) { // Take no damage from physics damages if ( info.GetDamageType() & DMG_CRUSH ) return 0; // Take the damage m_hPlayer->TakeDamage( info ); } return 0; }
int CNPC_Gargantua::OnTakeDamage_Alive( const CTakeDamageInfo &info ) { CTakeDamageInfo subInfo = info; float flDamage = subInfo.GetDamage(); if ( IsAlive() ) { if ( !(subInfo.GetDamageType() & GARG_DAMAGE) ) { flDamage *= 0.01; subInfo.SetDamage( flDamage ); } if ( subInfo.GetDamageType() & DMG_BLAST ) { SetCondition( COND_LIGHT_DAMAGE ); } } return BaseClass::OnTakeDamage_Alive( subInfo ); }
//--------------------------------------------------------- //--------------------------------------------------------- int CASW_Zombie::OnTakeDamage_Alive( const CTakeDamageInfo &info ) { #ifndef HL2_EPISODIC if ( info.GetDamageType() & DMG_BUCKSHOT ) { if( !m_fIsTorso && info.GetDamage() > (m_iMaxHealth/3) ) { // Always flinch if damaged a lot by buckshot, even if not shot in the head. // The reason for making sure we did at least 1/3rd of the zombie's max health // is so the zombie doesn't flinch every time the odd shotgun pellet hits them, // and so the maximum number of times you'll see a zombie flinch like this is 2.(sjb) AddGesture( ACT_GESTURE_FLINCH_HEAD ); } } #endif // HL2_EPISODIC // catching on fire int result = 0; // scale burning damage up if (dynamic_cast<CEntityFlame*>(info.GetAttacker())) { CTakeDamageInfo newDamage = info; newDamage.ScaleDamage(asw_fire_zombie_damage_scale.GetFloat()); result = BaseClass::OnTakeDamage_Alive(newDamage); } else { result = BaseClass::OnTakeDamage_Alive(info); } // if we take fire damage, catch on fire if (result > 0 && (info.GetDamageType() & DMG_BURN)) ASW_Ignite(30.0f, 0, info.GetAttacker()); //CASW_Marine* pMarine = dynamic_cast<CASW_Marine*>(info.GetAttacker()); //if (pMarine) //pMarine->HurtAlien(this); return BaseClass::OnTakeDamage_Alive( info ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CNPCSimpleTalker::OnTakeDamage_Alive( const CTakeDamageInfo &info ) { CTakeDamageInfo subInfo = info; // if player damaged this entity, have other friends talk about it. if (subInfo.GetAttacker() && (subInfo.GetAttacker()->GetFlags() & FL_CLIENT) && subInfo.GetDamage() < GetHealth() ) { CBaseEntity *pFriend = FindNearestFriend(false); if (pFriend && pFriend->IsAlive()) { // only if not dead or dying! CNPCSimpleTalker *pTalkNPC = (CNPCSimpleTalker *)pFriend; if (pTalkNPC && pTalkNPC->IsOkToCombatSpeak()) { pTalkNPC->Speak( TLK_NOSHOOT ); } } } return BaseClass::OnTakeDamage_Alive( subInfo ); }
//----------------------------------------------------------------------------- // Purpose: // Input : *pAttacker - // flDamage - // &vecDir - // *ptr - // bitsDamageType - //----------------------------------------------------------------------------- void CNPC_Bullseye::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { //If specified, we must be the enemy of the target if ( m_spawnflags & SF_BULLSEYE_ENEMYDAMAGEONLY ) { CAI_BaseNPC *pInstigator = info.GetAttacker()->MyNPCPointer(); if ( pInstigator == NULL ) return; if ( pInstigator->GetEnemy() != this ) return; } //We can bleed if we want to, we can leave decals behind... if ( ( m_spawnflags & SF_BULLSEYE_BLEED ) && ( m_takedamage == DAMAGE_NO ) ) { TraceBleed( info.GetDamage(), vecDir, ptr, info.GetDamageType() ); } BaseClass::TraceAttack( info, vecDir, ptr ); }
int CBaseTurret::OnTakeDamage( const CTakeDamageInfo &inputInfo ) { if ( !m_takedamage ) return 0; CTakeDamageInfo info = inputInfo; if (!m_iOn) info.ScaleDamage( 0.1f ); m_iHealth -= info.GetDamage(); if (m_iHealth <= 0) { m_iHealth = 0; m_takedamage = DAMAGE_NO; m_flDamageTime = gpGlobals->curtime; RemoveFlag( FL_NPC ); // why are they set in the first place??? SetThink(TurretDeath); m_OnDamaged.FireOutput( info.GetInflictor(), this ); SetNextThink( gpGlobals->curtime + 0.1f ); return 0; } if (m_iHealth <= 10) { if (m_iOn && (1 || random->RandomInt(0, 0x7FFF) > 800)) { m_fBeserk = 1; SetThink(SearchThink); } } return 1; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CPropCrane::OnTakeDamage( const CTakeDamageInfo &inputInfo ) { //Do scaled up physics damage to the car CTakeDamageInfo info = inputInfo; info.ScaleDamage( 25 ); // reset the damage info.SetDamage( inputInfo.GetDamage() ); //Check to do damage to driver if ( m_hPlayer != NULL ) { //Take no damage from physics damages if ( info.GetDamageType() & DMG_CRUSH ) return 0; //Take the damage m_hPlayer->TakeDamage( info ); } return 0; }
//========================================================= // TakeDamage - take damage. //========================================================= int CNPC_BaseTurret::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo ) { if ( m_takedamage == DAMAGE_NO ) return 0; float flDamage = inputInfo.GetDamage(); if (!m_iOn) flDamage /= 10.0; m_iHealth -= flDamage; if (m_iHealth <= 0) { m_iHealth = 0; m_takedamage = DAMAGE_NO; m_flDamageTime = gpGlobals->curtime; // ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? SetUse(NULL); SetThink(&CNPC_BaseTurret::TurretDeath); SetNextThink( gpGlobals->curtime + 0.1 ); m_OnDeactivate.FireOutput(this, this); return 0; } if (m_iHealth <= 10) { if (m_iOn) { m_fBeserk = 1; SetThink(&CNPC_BaseTurret::SearchThink); } } return 1; }
int CPhysicsCannister::OnTakeDamage( const CTakeDamageInfo &info ) { // HACKHACK: Shouldn't g_vecAttackDir be a parameter to this function? if ( !m_takedamage ) return 0; if ( !m_active ) { m_iHealth -= info.GetDamage(); if ( m_iHealth < 0 ) { Explode( info.GetAttacker() ); } else { // explosions that don't destroy will activate // 50% of the time blunt damage will activate as well if ( (info.GetDamageType() & DMG_BLAST) || ( (info.GetDamageType() & (DMG_CLUB|DMG_SLASH|DMG_CRUSH) ) && random->RandomInt(1,100) < 50 ) ) { CannisterActivate( info.GetAttacker(), g_vecAttackDir ); } } return 1; } if ( (gpGlobals->curtime - m_activateTime) <= 0.1 ) return 0; if ( info.GetDamageType() & (DMG_BULLET|DMG_BUCKSHOT|DMG_BURN|DMG_BLAST) ) { Explode( info.GetAttacker() ); } return 0; }
int OnTakeDamage( const CTakeDamageInfo &info ) { if ( m_iHealth <= info.GetDamage() ) m_iHealth = info.GetDamage() + TOO_MUCH_HEALTH_TO_DIE; return BaseClass::OnTakeDamage(info); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameStats::Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info, int iDamageTaken ) { CObjectSentrygun *pSentry = NULL; CTFPlayer *pTarget = ToTFPlayer( pBasePlayer ); CTFPlayer *pAttacker = ToTFPlayer( info.GetAttacker() ); if ( !pAttacker ) { pSentry = dynamic_cast< CObjectSentrygun * >( info.GetAttacker() ); if ( !pSentry ) return; pAttacker = pSentry->GetOwner(); if ( !pAttacker ) { // Sentry with no builder? Must be a pre-placed sentry. // It's easier to just cut off here and don't count damage. return; } } // don't count damage to yourself if ( pTarget == pAttacker ) return; IncrementStat( pAttacker, TFSTAT_DAMAGE, iDamageTaken ); TF_Gamestats_LevelStats_t::PlayerDamageLump_t damage; Vector killerOrg; // set the location where the target was hit const Vector &org = pTarget->GetAbsOrigin(); damage.nTargetPosition[ 0 ] = static_cast<int>( org.x ); damage.nTargetPosition[ 1 ] = static_cast<int>( org.y ); damage.nTargetPosition[ 2 ] = static_cast<int>( org.z ); // set the class of the attacker CBaseEntity *pInflictor = info.GetInflictor(); CBasePlayer *pScorer = TFGameRules()->GetDeathScorer( pAttacker, pInflictor, pTarget ); if ( !pSentry ) { pSentry = dynamic_cast< CObjectSentrygun * >( pInflictor ); } if ( pSentry != NULL ) { killerOrg = pSentry->GetAbsOrigin(); damage.iAttackClass = TF_CLASS_ENGINEER; damage.iWeapon = ( info.GetDamageType() & DMG_BLAST ) ? TF_WEAPON_SENTRY_ROCKET : TF_WEAPON_SENTRY_BULLET; } else if ( dynamic_cast<CObjectDispenser *>( pInflictor ) ) { damage.iAttackClass = TF_CLASS_ENGINEER; damage.iWeapon = TF_WEAPON_DISPENSER; } else { CTFPlayer *pTFAttacker = ToTFPlayer( pScorer ); if ( pTFAttacker ) { CTFPlayerClass *pAttackerClass = pTFAttacker->GetPlayerClass(); damage.iAttackClass = ( !pAttackerClass ) ? TF_CLASS_UNDEFINED : pAttackerClass->GetClassIndex(); killerOrg = pTFAttacker->GetAbsOrigin(); } else { damage.iAttackClass = TF_CLASS_UNDEFINED; killerOrg = org; } // find the weapon the killer used damage.iWeapon = GetWeaponFromDamage( info ); } // If normal gameplay state, track weapon stats. if ( ( TFGameRules()->State_Get() == GR_STATE_RND_RUNNING ) && ( damage.iWeapon != TF_WEAPON_NONE ) ) { // record hits & damage in reported per-weapon stats if ( m_reportedStats.m_pCurrentGame != NULL ) { TF_Gamestats_WeaponStats_t *pWeaponStats = &m_reportedStats.m_pCurrentGame->m_aWeaponStats[damage.iWeapon]; pWeaponStats->iHits++; pWeaponStats->iTotalDamage += iDamageTaken; // Try and figure out where the damage is coming from Vector vecDamageOrigin = info.GetReportedPosition(); // If we didn't get an origin to use, try using the attacker's origin if ( vecDamageOrigin == vec3_origin ) { if ( pSentry ) { vecDamageOrigin = pSentry->GetAbsOrigin(); } else { vecDamageOrigin = killerOrg; } } if ( vecDamageOrigin != vec3_origin ) { pWeaponStats->iHitsWithKnownDistance++; int iDistance = (int) vecDamageOrigin.DistTo( pBasePlayer->GetAbsOrigin() ); // Msg( "Damage distance: %d\n", iDistance ); pWeaponStats->iTotalDistance += iDistance; } } } Assert( damage.iAttackClass != TF_CLASS_UNDEFINED ); // record the time the damage occurred damage.fTime = gpGlobals->curtime; // store the attacker's position damage.nAttackerPosition[ 0 ] = static_cast<int>( killerOrg.x ); damage.nAttackerPosition[ 1 ] = static_cast<int>( killerOrg.y ); damage.nAttackerPosition[ 2 ] = static_cast<int>( killerOrg.z ); // set the class of the target CTFPlayer *pTFPlayer = ToTFPlayer( pTarget ); CTFPlayerClass *pTargetClass = ( pTFPlayer ) ? pTFPlayer->GetPlayerClass() : NULL; damage.iTargetClass = ( !pTargetClass ) ? TF_CLASS_UNDEFINED : pTargetClass->GetClassIndex(); Assert( damage.iTargetClass != TF_CLASS_UNDEFINED ); // record the damage done damage.iDamage = info.GetDamage(); // record if it was a crit damage.iCrit = ( ( info.GetDamageType() & DMG_CRITICAL ) != 0 ); // record if it was a kill damage.iKill = ( pTarget->GetHealth() <= 0 ); // add it to the list of damages if ( m_reportedStats.m_pCurrentGame != NULL ) { m_reportedStats.m_pCurrentGame->m_aPlayerDamage.AddToTail( damage ); } }
// Add the ability to ignore the world trace void CSDKGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, bool bIgnoreWorld ) { CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecToTarget; Vector vecEndPos; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; vecSrc.z += 1;// in case grenade is lying on the ground // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if ( pEntity->m_takedamage != DAMAGE_NO ) { // 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; // radius damage can only be blocked by the world vecSpot = pEntity->BodyTarget( vecSrc ); bool bHit = false; if( bIgnoreWorld ) { vecEndPos = vecSpot; bHit = true; } else { UTIL_TraceLine( vecSrc, vecSpot, MASK_SOLID_BRUSHONLY, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } vecEndPos = tr.endpos; if( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { bHit = true; } } if ( bHit ) { // the explosion can 'see' this entity, so hurt them! //vecToTarget = ( vecSrc - vecEndPos ); vecToTarget = ( vecEndPos - vecSrc ); // decrease damage for an ent that's farther from the bomb. flAdjustedDamage = vecToTarget.Length() * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage > 0 ) { CTakeDamageInfo adjustedInfo = info; adjustedInfo.SetDamage( flAdjustedDamage ); Vector dir = vecToTarget; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ ); } 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 ); } pEntity->TakeDamage( adjustedInfo ); // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecEndPos, dir ); } } } } }
//----------------------------------------------------------------------------- // 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; }
int CE_Cycler_Fix::OnTakeDamage_Alive(const CTakeDamageInfo& info) { #if 0 return BaseClass::OnTakeDamage_Alive(info); #endif Forget( bits_MEMORY_INCOVER ); if ( !CCombatCharacter::FAKE_OnTakeDamage_Alive( info ) ) return 0; if ( GetSleepState() == AISS_WAITING_FOR_THREAT ) Wake(); CEntity *attacker = CEntity::Instance(info.GetAttacker()); // NOTE: This must happen after the base class is called; we need to reduce // health before the pain sound, since some NPCs use the final health // level as a modifier to determine which pain sound to use. // REVISIT: Combine soldiers shoot each other a lot and then talk about it // this improves that case a bunch, but it seems kind of harsh. if ( !GetSquad() || !GetSquad()->SquadIsMember( attacker ) ) { PainSound( info );// "Ouch!" } // See if we're running a dynamic interaction that should break when I am damaged. if ( IsActiveDynamicInteraction() ) { ScriptedNPCInteraction_t *pInteraction = GetRunningDynamicInteraction(); if ( pInteraction->iLoopBreakTriggerMethod & SNPCINT_LOOPBREAK_ON_DAMAGE ) { CEAI_ScriptedSequence *_m_hCine = Get_m_hCine(); // Can only break when we're in the action anim if ( _m_hCine->IsPlayingAction() ) { _m_hCine->StopActionLoop( true ); } } } // If we're not allowed to die, refuse to die // Allow my interaction partner to kill me though if ( m_iHealth <= 0 && HasInteractionCantDie() && attacker != m_hInteractionPartner ) { m_iHealth = 1; } // ----------------------------------- // Fire outputs // ----------------------------------- if ( m_flLastDamageTime != gpGlobals->curtime ) { // only fire once per frame m_OnDamaged->FireOutput( attacker, this); if( attacker && attacker->IsPlayer() ) { m_OnDamagedByPlayer->FireOutput( attacker, this ); // This also counts as being harmed by player's squad. m_OnDamagedByPlayerSquad->FireOutput( attacker, this ); } else { // See if the person that injured me is an NPC. CAI_NPC *pAttacker = dynamic_cast<CAI_NPC *>( attacker ); if( pAttacker && pAttacker->IsAlive() ) { if( pAttacker->GetSquad() != NULL && pAttacker->IsInPlayerSquad() ) { m_OnDamagedByPlayerSquad->FireOutput( attacker, this ); } } } } if( (info.GetDamageType() & DMG_CRUSH) && !(info.GetDamageType() & DMG_PHYSGUN) && info.GetDamage() >= MIN_PHYSICS_FLINCH_DAMAGE ) { SetCondition( COND_PHYSICS_DAMAGE ); } if ( m_iHealth <= ( m_iMaxHealth / 2 ) ) { m_OnHalfHealth->FireOutput( attacker, this ); } // react to the damage (get mad) if ( ( (GetFlags() & FL_NPC) == 0 ) || !attacker ) return 1; // If the attacker was an NPC or client update my position memory if ( attacker->GetFlags() & (FL_NPC | FL_CLIENT) ) { // ------------------------------------------------------------------ // DO NOT CHANGE THIS CODE W/O CONSULTING // Only update information about my attacker I don't see my attacker // ------------------------------------------------------------------ if ( !FInViewCone_Entity( info.GetAttacker() ) || !FVisible_Entity( info.GetAttacker() ) ) { // ------------------------------------------------------------- // If I have an inflictor (enemy / grenade) update memory with // position of inflictor, otherwise update with an position // estimate for where the attack came from // ------------------------------------------------------ Vector vAttackPos; CEntity *inflictor = CEntity::Instance(info.GetInflictor()); if (inflictor) { vAttackPos = inflictor->GetAbsOrigin(); } else { vAttackPos = (GetAbsOrigin() + ( *g_vecAttackDir * 64 )); } // ---------------------------------------------------------------- // If I already have an enemy, assume that the attack // came from the enemy and update my enemy's position // unless I already know about the attacker or I can see my enemy // ---------------------------------------------------------------- if ( GetEnemy() != NULL && !GetEnemies()->HasMemory( info.GetAttacker() ) && !HasCondition(COND_SEE_ENEMY) ) { UpdateEnemyMemory(GetEnemy_CBase(), vAttackPos, GetEnemy_CBase()); } // ---------------------------------------------------------------- // If I already know about this enemy, update his position // ---------------------------------------------------------------- else if (GetEnemies()->HasMemory( info.GetAttacker() )) { UpdateEnemyMemory(info.GetAttacker(), vAttackPos); } // ----------------------------------------------------------------- // Otherwise just note the position, but don't add enemy to my list // ----------------------------------------------------------------- else { UpdateEnemyMemory(NULL, vAttackPos); } } // add pain to the conditions if ( IsLightDamage( info ) ) { SetCondition( COND_LIGHT_DAMAGE ); } if ( IsHeavyDamage( info ) ) { SetCondition( COND_HEAVY_DAMAGE ); } ForceGatherConditions(); // Keep track of how much consecutive damage I have recieved if ((gpGlobals->curtime - m_flLastDamageTime) < 1.0) { m_flSumDamage += info.GetDamage(); } else { m_flSumDamage = info.GetDamage(); } m_flLastDamageTime = gpGlobals->curtime; if ( attacker && attacker->IsPlayer() ) m_flLastPlayerDamageTime = gpGlobals->curtime; GetEnemies()->OnTookDamageFrom( info.GetAttacker() ); if (m_flSumDamage > m_iMaxHealth*0.3) { SetCondition(COND_REPEATED_DAMAGE); } NotifyFriendsOfDamage( info.GetAttacker() ); } // --------------------------------------------------------------- // Insert a combat sound so that nearby NPCs know I've been hit // --------------------------------------------------------------- g_helpfunc.CSoundEnt_InsertSound(SOUND_COMBAT, GetAbsOrigin(), 1024, 0.5, BaseEntity(), SOUNDENT_CHANNEL_INJURY ); return 1; }
//----------------------------------------------------------------------------- // Purpose: Bullseyes should always report light damage if any amount of damage is taken // Input : fDamage - amount of damage // bitsDamageType - damage type //----------------------------------------------------------------------------- bool CNPC_Bullseye::IsLightDamage( const CTakeDamageInfo &info ) { return ( info.GetDamage() > 0 ); }
//----------------------------------------------------------------------------- // 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 CASW_Alien::Bleed( const CTakeDamageInfo &info, const Vector &vecPos, const Vector &vecDir, trace_t *ptr ) { UTIL_ASW_DroneBleed( vecPos, -vecDir, 4 ); DoBloodDecal( info.GetDamage(), vecPos, vecDir, ptr, info.GetDamageType() ); }
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: 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(); } } }
Vector QUA_helicopter::CalcDamageForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if (info.GetDamageForce() != vec3_origin || (info.GetDamageType() & /*DMG_NO_PHYSICS_FORCE*/DMG_BLAST)) { //if( info.GetDamageType() & DMG_BLAST ) //{ // Fudge blast forces a little bit, so that each // victim gets a slightly different trajectory. // This simulates features that usually vary from // person-to-person variables such as bodyweight, // which are all indentical for characters using the same model. 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; }
//----------------------------------------------------------------------------- // Purpose: SecobModportal1s should always report light damage if any amount of damage is taken // Input : fDamage - amount of damage // bitsDamageType - damage type //----------------------------------------------------------------------------- bool CNPC_SecobModportal1::IsLightDamage( const CTakeDamageInfo &info ) { return ( info.GetDamage() > 0 ); }
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 } }
void CBaseGameStats::Event_WeaponHit( CBasePlayer *pShooter, bool bPrimary, char const *pchWeaponName, const CTakeDamageInfo &info ) { StatsLog( "CBaseGameStats::Event_WeaponHit [%s] %s weapon [%s] damage [%f]\n", pShooter->GetPlayerName(), bPrimary ? "primary" : "secondary", pchWeaponName, info.GetDamage() ); }
//----------------------------------------------------------------------------- // 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 ); }
void CWeaponDrainGrenade::RadiusDamage( const CTakeDamageInfo &inputInfo, const Vector &vecSrcIn, float flRadius ) { CTakeDamageInfo info = inputInfo; CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecToTarget; Vector vecEndPos; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; vecSrc.z += 1;// in case grenade is lying on the ground // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if (!pEntity || !ToCFPlayer(pEntity)) continue; // Don't drain teammates. if (CFGameRules()->PlayerRelationship(GetThrower(), pEntity) == GR_TEAMMATE && ToCFPlayer(pEntity) != ToCFPlayer(GetThrower())) continue; if ( !pEntity->IsAlive() ) continue; if ( pEntity->m_takedamage != DAMAGE_NO ) { // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // radius damage can only be blocked by the world vecSpot = pEntity->BodyTarget( vecSrc ); bool bHit = false; UTIL_TraceLine( vecSrc, vecSpot, MASK_SOLID_BRUSHONLY, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } vecEndPos = tr.endpos; if( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { bHit = true; } if ( bHit ) { // the explosion can 'see' this entity, so hurt them! vecToTarget = ( vecEndPos - vecSrc ); // decrease damage for an ent that's farther from the blast's center. flAdjustedDamage = vecToTarget.Length() * falloff; flAdjustedDamage = info.GetDrainFocus() - flAdjustedDamage; if ( flAdjustedDamage > 0 ) { CTakeDamageInfo adjustedInfo = info; adjustedInfo.SetDrainFocus( flAdjustedDamage ); Vector dir = vecToTarget; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ ); } 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 ); } float flFocusDrained = adjustedInfo.GetDrainFocus(); float& flFocus = ToCFPlayer(pEntity)->m_pStats->m_flFocus.GetForModify(); if (flFocus > cf_minfocusdrain.GetFloat()) flFocus -= flFocusDrained; if (flFocus < cf_minfocusdrain.GetFloat()) flFocus = cf_minfocusdrain.GetFloat(); CEffectData data; data.m_nHitBox = GetParticleSystemIndex( "grenade_drained" ); data.m_vOrigin = ToCFPlayer(pEntity)->GetCentroid(); data.m_vStart = vecSrc; data.m_vAngles = QAngle(0,0,0); data.m_nEntIndex = pEntity->entindex(); data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; data.m_nDamageType = PATTACH_CUSTOMORIGIN; DispatchEffect( "ParticleEffect", data ); // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecEndPos, dir ); } } } } }