/* ============ TakeDamage The damage is coming from inflictor, but get mad at attacker This should be the only function that ever reduces health. bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK Time-based damage: only occurs while the monster is within the trigger_hurt. When a monster is poisoned via an arrow etc it takes all the poison damage at once. GLOBALS ASSUMED SET: g_iSkillLevel ============ */ int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { float flTake; Vector vecDir; if (!pev->takedamage) return 0; if ( !IsAlive() ) { return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } if ( pev->deadflag == DEAD_NO ) { // no pain sound during death animation. PainSound();// "Ouch!" } //!!!LATER - make armor consideration here! flTake = flDamage; // set damage type sustained m_bitsDamageType |= bitsDamageType; // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). vecDir = Vector( 0, 0, 0 ); if (!FNullEnt( pevInflictor )) { CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); if (pInflictor) { vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); vecDir = g_vecAttackDir = vecDir.Normalize(); } } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // todo: remove after combining shotgun blasts? if ( IsPlayer() ) { if ( pevInflictor ) pev->dmg_inflictor = ENT(pevInflictor); pev->dmg_take += flTake; // check for godmode or invincibility if ( pev->flags & FL_GODMODE ) { return 0; } } // if this is a player, move him around! if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) ) { pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); } // do the damage pev->health -= flTake; // HACKHACK Don't kill monsters in a script. Let them break their scripts first if ( m_MonsterState == MONSTERSTATE_SCRIPT ) { SetConditions( bits_COND_LIGHT_DAMAGE ); return 0; } if ( pev->health <= 0 ) { g_pevLastInflictor = pevInflictor; if ( bitsDamageType & DMG_ALWAYSGIB ) { Killed( pevAttacker, GIB_ALWAYS ); } else if ( bitsDamageType & DMG_NEVERGIB ) { Killed( pevAttacker, GIB_NEVER ); } else { Killed( pevAttacker, GIB_NORMAL ); } g_pevLastInflictor = NULL; return 0; } // react to the damage (get mad) if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) { //LRC - new behaviours, for m_iPlayerReact. if (pevAttacker->flags & FL_CLIENT) { if (m_iPlayerReact == 2) { // just get angry. Remember( bits_MEMORY_PROVOKED ); } else if (m_iPlayerReact == 3) { // try to decide whether it was deliberate... if I have an enemy, assume it was just crossfire. if ( m_hEnemy == 0 ) { if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || UTIL_IsFacing( pevAttacker, pev->origin ) ) Remember( bits_MEMORY_PROVOKED ); else Remember( bits_MEMORY_SUSPICIOUS ); } } } if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) {// only if the attack was a monster or client! // enemy's last known position is somewhere down the vector that the attack came from. if (pevInflictor) { if (m_hEnemy == 0 || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) { m_vecEnemyLKP = pevInflictor->origin; } } else { m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); } MakeIdealYaw( m_vecEnemyLKP ); // add pain to the conditions // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and // heavy damage per monster class? if ( flDamage > 0 ) { SetConditions(bits_COND_LIGHT_DAMAGE); } if ( flDamage >= 20 ) { SetConditions(bits_COND_HEAVY_DAMAGE); } } } return 1; }
int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) { // make sure friends talk about it if player hurts talkmonsters... int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); if ( !IsAlive() || pev->deadflag == DEAD_DYING ) return ret; // LRC - if my reaction to the player has been overridden, don't do this stuff if (m_iPlayerReact) return ret; if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) ) { m_flPlayerDamage += flDamage; // This is a heurstic to determine if the player intended to harm me // If I have an enemy, we can't establish intent (may just be crossfire) if ( m_hEnemy == NULL ) { // If the player was facing directly at me, or I'm already suspicious, get mad if( (m_afMemory & bits_MEMORY_SUSPICIOUS) || UTIL_IsFacing( pevAttacker, GetAbsOrigin() )) { // Alright, now I'm pissed! if (m_iszSpeakAs) { char szBuf[32]; strcpy(szBuf,STRING(m_iszSpeakAs)); strcat(szBuf,"_MAD"); PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); } else { PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM ); } Remember( bits_MEMORY_PROVOKED ); StopFollowing( TRUE ); } else { // Hey, be careful with that if (m_iszSpeakAs) { char szBuf[32]; strcpy(szBuf,STRING(m_iszSpeakAs)); strcat(szBuf,"_SHOT"); PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); } else { PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); } Remember( bits_MEMORY_SUSPICIOUS ); } } else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) { if (m_iszSpeakAs) { char szBuf[32]; strcpy(szBuf,STRING(m_iszSpeakAs)); strcat(szBuf,"_SHOT"); PlaySentence( szBuf, 4, VOL_NORM, ATTN_NORM ); } else { PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); } } } return ret; }