diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 46d6a5628..2ab51a89e 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -192,7 +192,7 @@ void DamageInfo::AbsorbDamage(uint32 amount) amount = std::min(amount, GetDamage()); m_absorb += amount; m_damage -= amount; - m_hitMask |= PROC_HIT_ABSORB;m_damage -= amount; + m_hitMask |= PROC_HIT_ABSORB; } void DamageInfo::ResistDamage(uint32 amount) @@ -1413,8 +1413,11 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama // double blocked amount if block is critical if (victim->isBlockCritical()) damageInfo->blocked *= 2; - if (damage < int32(damageInfo->blocked)) + if (damage <= int32(damageInfo->blocked)) + { damageInfo->blocked = uint32(damage); + damageInfo->fullBlock = true; + } damage -= damageInfo->blocked; cleanDamage += damageInfo->blocked; @@ -1468,14 +1471,18 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damageInfo->damage = std::max(0, damage); // Calculate absorb resist - if (damageInfo->damage > 0) - { - DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, 0); - Unit::CalcAbsorbResist(dmgInfo); - damageInfo->absorb = dmgInfo.GetAbsorb(); - damageInfo->resist = dmgInfo.GetResist(); - damageInfo->damage = dmgInfo.GetDamage(); - } + DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, PROC_HIT_NONE); + Unit::CalcAbsorbResist(dmgInfo); + damageInfo->absorb = dmgInfo.GetAbsorb(); + damageInfo->resist = dmgInfo.GetResist(); + + if (damageInfo->absorb) + damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB); + + if (damageInfo->resist) + damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST); + + damageInfo->damage = dmgInfo.GetDamage(); } void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss, Spell const* spell /*= nullptr*/) @@ -2070,31 +2077,25 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) } // Ignore Absorption Auras - float auraAbsorbMod = 0; - if (attacker) + float auraAbsorbMod = victim->GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, dmgInfo.GetSchoolMask());; + AuraEffectList const& abilityAbsorbAuras = victim->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL); + for (AuraEffect const* aurEff : abilityAbsorbAuras) { - AuraEffectList const& AbsIgnoreAurasA = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL); - for (AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr) - { - if (!((*itr)->GetMiscValue() & schoolMask)) - continue; + if (!(aurEff->GetMiscValue() & schoolMask)) + continue; - if ((*itr)->GetAmount() > auraAbsorbMod) - auraAbsorbMod = float((*itr)->GetAmount()); - } + if (!aurEff->IsAffectedOnSpell(spellInfo)) + continue; - AuraEffectList const& AbsIgnoreAurasB = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL); - for (AuraEffectList::const_iterator itr = AbsIgnoreAurasB.begin(); itr != AbsIgnoreAurasB.end(); ++itr) - { - if (!((*itr)->GetMiscValue() & schoolMask)) - continue; - - if (((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo)) - auraAbsorbMod = float((*itr)->GetAmount()); - } - RoundToInterval(auraAbsorbMod, 0.0f, 100.0f); + if (aurEff->GetAmount() > auraAbsorbMod) + auraAbsorbMod = float(aurEff->GetAmount()); } + RoundToInterval(auraAbsorbMod, 0.f, 100.f); + + int32 absorbIgnoringDamage = CalculatePct(dmgInfo.GetDamage(), auraAbsorbMod); + dmgInfo.ModifyDamage(-absorbIgnoringDamage); + // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB)); @@ -12190,14 +12191,13 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond hitMask |= PROC_HIT_PARRY; break; case SPELL_MISS_BLOCK: - hitMask |= PROC_HIT_BLOCK; + // spells can't be partially blocked (it's damage can though) + hitMask |= PROC_HIT_BLOCK | PROC_HIT_FULL_BLOCK; break; case SPELL_MISS_EVADE: hitMask |= PROC_HIT_EVADE; break; case SPELL_MISS_IMMUNE: - hitMask |= PROC_HIT_IMMUNE; - break; case SPELL_MISS_IMMUNE2: hitMask |= PROC_HIT_IMMUNE; break; @@ -12210,6 +12210,9 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond case SPELL_MISS_REFLECT: hitMask |= PROC_HIT_REFLECT; break; + case SPELL_MISS_RESIST: + hitMask |= PROC_HIT_FULL_RESIST; + break; default: break; } @@ -12218,15 +12221,27 @@ uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCond { // On block if (damageInfo->blocked) + { hitMask |= PROC_HIT_BLOCK; + if (damageInfo->fullBlock) + hitMask |= PROC_HIT_FULL_BLOCK; + } // On absorb if (damageInfo->absorb) hitMask |= PROC_HIT_ABSORB; - // On crit - if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) - hitMask |= PROC_HIT_CRITICAL; - else - hitMask |= PROC_HIT_NORMAL; + + // Don't set hit/crit hitMask if damage is nullified + bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0; + if (!damageNullified) + { + // On crit + if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT) + hitMask |= PROC_HIT_CRITICAL; + else + hitMask |= PROC_HIT_NORMAL; + } + else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0) + hitMask |= PROC_HIT_FULL_RESIST; } return hitMask; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index d15b141bf..8e66a0a48 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -891,7 +891,7 @@ struct SpellNonMeleeDamage { SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellInfo const* _spellInfo, uint32 _schoolMask) : target(_target), attacker(_attacker), spellInfo(_spellInfo), damage(0), overkill(0), schoolMask(_schoolMask), - absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) + absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0), fullBlock(false) {} Unit* target; @@ -908,6 +908,7 @@ struct SpellNonMeleeDamage uint32 HitInfo; // Used for help uint32 cleanDamage; + bool fullBlock; }; struct SpellPeriodicAuraLogInfo diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 46a5ef1e9..6b195ff72 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -6468,7 +6468,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const if (damage) { procVictim |= PROC_FLAG_TAKEN_DAMAGE; - hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; + hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; } int32 overkill = damage - target->GetHealth(); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 0d544bf1f..b847c8f13 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -311,6 +311,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) else { DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); + m_caster->CalcAbsorbResist(dmgInfo); uint32 absorb = dmgInfo.GetAbsorb(); uint32 resist = dmgInfo.GetResist();