//----------------------------------------------------------------------------- // Purpose: Player has taken some damage. This is now using the Quake functionality. //----------------------------------------------------------------------------- int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { if ( (pev->takedamage == DAMAGE_NO) || (IsAlive() == FALSE) ) return 0; //We are wearing the suit and we want to be hurt by lava or slime if ( m_iQuakeItems & IT_SUIT ) { if ( bitsDamageType & DMG_BURN || bitsDamageType & DMG_ACID ) return 0; } CBaseEntity *pAttacker = CBaseEntity::Instance(pevAttacker); // keep track of amount of damage last sustained m_lastDamageAmount = flDamage; // check for quad damage powerup on the attacker if (pAttacker->IsPlayer()) { if ( ((CBasePlayer*)pAttacker)->m_flSuperDamageFinished > gpGlobals->time ) { if (gpGlobals->deathmatch == 4) flDamage *= 8; else flDamage *= 4; } } // team play damage avoidance if ( g_pGameRules->PlayerRelationship( this, pAttacker ) == GR_TEAMMATE ) { // Teamplay 3 you can still hurt yourself if ( CVAR_GET_FLOAT( "mp_teamplay" ) == 3 && pAttacker != this ) return 0; // Teamplay 1 can't hurt any teammates, including yourself if ( CVAR_GET_FLOAT( "mp_teamplay" ) == 1 ) return 0; // Teamplay 2 you can still hurt teammates } // save damage based on the target's armor level float flSave = ceil(pev->armortype * flDamage); if (flSave >= pev->armorvalue) { flSave = pev->armorvalue; pev->armortype = 0; // lost all armor m_iQuakeItems &= ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3); } pev->armorvalue -= flSave; float flTake = ceil(flDamage - flSave); // add to the damage total for clients, which will be sent as a single message at the end of the frame pev->dmg_take = pev->dmg_take + flTake; pev->dmg_inflictor = ENT(pevInflictor); Vector vecTemp; if ( pevAttacker == pevInflictor ) { vecTemp = pevAttacker->origin - ( VecBModelOrigin(pev) ); } else // an actual missile was involved. { vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); } // this global is still used for glass and other non-monster killables, along with decals. g_vecAttackDir = vecTemp.Normalize(); // figure momentum add if ( (pevInflictor) && (pev->movetype == MOVETYPE_WALK) && !( FBitSet (bitsDamageType, DMG_BURN) ) && !( FBitSet (bitsDamageType, DMG_ACID) ) ) { Vector vecPush = (pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5).Normalize(); // Set kickback for smaller weapons // Read: only if it's not yourself doing the damage if ( (flDamage < 60) && pAttacker->IsPlayer() && (pAttacker != this) ) pev->velocity = pev->velocity + vecPush * flDamage * 11; else { // Otherwise, these rules apply to rockets and grenades // for blast velocity if ( pAttacker == this ) { if ( m_iQuakeWeapon != IT_LIGHTNING ) pev->velocity = pev->velocity + vecPush * flDamage * 8; } else pev->velocity = pev->velocity + vecPush * flDamage * 8; } // Rocket Jump modifiers int iRocketJumpModifier = (int)CVAR_GET_FLOAT("rj"); if ( (iRocketJumpModifier > 1) && (pAttacker == this) && m_iQuakeWeapon == ( IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER ) ) pev->velocity = pev->velocity + vecPush * flDamage * iRocketJumpModifier; } // check for godmode or invincibility if (pev->flags & FL_GODMODE) return 0; if (m_flInvincibleFinished > gpGlobals->time) { if (m_fInvincSound < gpGlobals->time) { EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM); m_fInvincSound = gpGlobals->time + 2; } return 0; } // do the damage pev->health -= (int)flTake; // tell director about it MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); WRITE_BYTE ( 9 ); // command length in bytes WRITE_BYTE ( DRC_CMD_EVENT ); // take damage event WRITE_SHORT( ENTINDEX(this->edict()) ); // index number of primary entity WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity WRITE_LONG( 5 ); // eventflags (priority and flags) MESSAGE_END(); // react to the damage m_bitsDamageType |= bitsDamageType; // Save this so we can report it to the client m_bitsHUDDamage = -1; // make sure the damage bits get resent if ( pev->health <= 0 ) { g_pevLastInflictor = pevInflictor; Killed( pevAttacker, GIB_NORMAL ); g_pevLastInflictor = NULL; return 0; } // play pain sound Pain( pAttacker ); return flTake; }
/* ============ idActor::Damage this entity that is being damaged inflictor entity that is causing the damage attacker entity that caused the inflictor to damage targ example: this=monster, inflictor=rocket, attacker=player dir direction of the attack for knockback in global space point point at which the damage is being inflicted, used for headshots damage amount of damage being inflicted inflictor, attacker, dir, and point can be NULL for environmental effects Bleeding wounds and surface overlays are applied in the collision code that calls Damage() ============ */ void idActor::Damage( idEntity *inflictor, idEntity *attacker, const noVec3 &dir, const char *damageDefName, const float damageScale, const int location ) { if ( !fl.takedamage ) { return; } if ( !inflictor ) { inflictor = gameLocal.world; } if ( !attacker ) { attacker = gameLocal.world; } #if 0 #ifdef _D3XP SetTimeState ts( timeGroup ); // Helltime boss is immune to all projectiles except the helltime killer if ( finalBoss && idStr::Icmp(inflictor->GetEntityDefName(), "projectile_helltime_killer") ) { return; } // Maledict is immume to the falling asteroids if ( !idStr::Icmp( GetEntityDefName(), "monster_boss_d3xp_maledict" ) && (!idStr::Icmp( damageDefName, "damage_maledict_asteroid" ) || !idStr::Icmp( damageDefName, "damage_maledict_asteroid_splash" ) ) ) { return; } #else if ( finalBoss && !inflictor->IsType( idSoulCubeMissile::Type ) ) { return; } #endif #endif const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName ); if ( !damageDef ) { gameLocal.Error( "Unknown damageDef '%s'", damageDefName ); } int damage = damageDef->GetInt( "damage" ) * damageScale; damage = GetDamageForLocation( damage, location ); // inform the attacker that they hit someone attacker->DamageFeedback( this, inflictor, damage ); if ( damage > 0 ) { health -= damage; #ifdef _D3XP //Check the health against any damage cap that is currently set if(damageCap >= 0 && health < damageCap) { health = damageCap; } #endif if ( health <= 0 ) { if ( health < -999 ) { health = -999; } Killed( inflictor, attacker, damage, dir, location ); if ( ( health < -20 ) && spawnArgs.GetBool( "gib" ) && damageDef->GetBool( "gib" ) ) { Gib( dir, damageDefName ); } } else { Pain( inflictor, attacker, damage, dir, location ); } } else { // don't accumulate knockback if ( af.IsLoaded() ) { // clear impacts af.Rest(); // physics is turned off by calling af.Rest() BecomeActive( TH_PHYSICS ); } } }