diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 177f92f00..f0a82c347 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -784,12 +784,21 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) // Absorb, resist some environmental damage type uint32 absorb = 0; uint32 resist = 0; - if (type == DAMAGE_LAVA) - Unit::CalcAbsorbResist(this, this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist); - else if (type == DAMAGE_SLIME) - Unit::CalcAbsorbResist(this, this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist); - damage -= absorb + resist; + switch (type) + { + case DAMAGE_LAVA: + case DAMAGE_SLIME: + { + DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE); + Unit::CalcAbsorbResist(dmgInfo); + absorb = dmgInfo.GetAbsorb(); + resist = dmgInfo.GetResist(); + damage = dmgInfo.GetDamage(); + } + default: + break; + } Unit::DealDamageMods(this, damage, &absorb); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index f086fe0c1..2df8d0e00 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -109,21 +109,28 @@ static bool isAlwaysTriggeredAura[TOTAL_AURAS]; // Prepare lists static bool procPrepared = InitTriggerAuraData(); -DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType) +DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage) : m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask), - m_damageType(_damageType), m_attackType(BASE_ATTACK) + m_damageType(_damageType), m_attackType(BASE_ATTACK), m_cleanDamage(cleanDamage) { m_absorb = 0; m_resist = 0; m_block = 0; } + DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo) : m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)), - m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType) + m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType), m_absorb(dmgInfo.absorb), m_resist(dmgInfo.resist), m_block(dmgInfo.blocked_amount), + m_cleanDamage(dmgInfo.cleanDamage) +{ +} + +DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType) + : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage), + m_spellInfo(spellNonMeleeDamage.spellInfo), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType), + m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), + m_cleanDamage(spellNonMeleeDamage.cleanDamage) { - m_absorb = 0; - m_resist = 0; - m_block = 0; } void DamageInfo::ModifyDamage(int32 amount) @@ -153,6 +160,11 @@ void DamageInfo::BlockDamage(uint32 amount) m_damage -= amount; } +uint32 DamageInfo::GetUnmitigatedDamage() const +{ + return m_damage + m_cleanDamage + m_absorb + m_resist; +} + ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell const* spell, DamageInfo* damageInfo, HealInfo* healInfo, SpellInfo const* triggeredByAuraSpell, int8 procAuraEffectIndex) : _actor(actor), _actionTarget(actionTarget), _procTarget(procTarget), _typeMask(typeMask), _spellTypeMask(spellTypeMask), _spellPhaseMask(spellPhaseMask), _hitMask(hitMask), _spell(spell), _damageInfo(damageInfo), _healInfo(healInfo), _triggeredByAuraSpell(triggeredByAuraSpell), _procAuraEffectIndex(procAuraEffectIndex) @@ -810,13 +822,16 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage } else { + DamageInfo sharedDamageInfo(attacker, shareDamageTarget, shareDamage, spellProto, damageSchoolMask, damagetype); + Unit::CalcAbsorbResist(sharedDamageInfo, true); + shareAbsorb = sharedDamageInfo.GetAbsorb(); + shareResist = sharedDamageInfo.GetResist(); + shareDamage = sharedDamageInfo.GetDamage(); Unit::DealDamageMods(shareDamageTarget, shareDamage, &shareAbsorb); - Unit::CalcAbsorbResist(attacker, shareDamageTarget, damageSchoolMask, damagetype, shareDamage, &shareAbsorb, &shareResist, spellProto, true); - shareDamage -= std::min(shareAbsorb, shareDamage); } if (attacker && shareDamageTarget->GetTypeId() == TYPEID_PLAYER) - attacker->SendSpellNonMeleeDamageLog(shareDamageTarget, spell->Id, shareDamage + shareAbsorb + shareResist, damageSchoolMask, shareAbsorb, shareResist, damagetype == DIRECT_DAMAGE, 0, false); + attacker->SendSpellNonMeleeDamageLog(shareDamageTarget, spell, shareDamage, damageSchoolMask, shareAbsorb, shareResist, damagetype == DIRECT_DAMAGE, 0, false); Unit::DealDamage(attacker, shareDamageTarget, shareDamage, cleanDamage, NODAMAGE, damageSchoolMask, spellProto, false); } @@ -1180,8 +1195,16 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask); uint32 crTypeMask = victim->GetCreatureTypeMask(); + // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations + sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage); + if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo)) - damage = Unit::CalcArmorReducedDamage(this, victim, damage, spellInfo, 0, attackType); + { + damageInfo->damage = Unit::CalcArmorReducedDamage(this, victim, damage, spellInfo, 0, attackType); + damageInfo->cleanDamage += damage - damageInfo->damage; + } + else + damageInfo->damage = damage; bool blocked = false; // Per-school calc @@ -1203,11 +1226,11 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; // Calculate crit bonus - uint32 crit_bonus = damage; + uint32 crit_bonus = damageInfo->damage; // Apply crit_damage bonus for melee spells if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); - damage += crit_bonus; + damageInfo->damage += crit_bonus; // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE float critPctDamageMod = 0.0f; @@ -1223,7 +1246,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask); if (critPctDamageMod != 0) - AddPct(damage, critPctDamageMod); + AddPct(damageInfo->damage, critPctDamageMod); } // Spell weapon based damage CAN BE crit & blocked at same time @@ -1232,19 +1255,26 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama damageInfo->blocked = victim->GetShieldBlockValue(); // double blocked amount if block is critical if (victim->isBlockCritical()) - damageInfo->blocked += damageInfo->blocked; + damageInfo->blocked *= 2; if (damage < int32(damageInfo->blocked)) damageInfo->blocked = uint32(damage); - damage -= damageInfo->blocked; + + damageInfo->damage -= damageInfo->blocked; + damageInfo->cleanDamage += damageInfo->blocked; } + int32 resilienceReduction = damageInfo->damage; if (CanApplyResilience()) { if (attackType != RANGED_ATTACK) - Unit::ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_MELEE); + Unit::ApplyResilience(victim, nullptr, &resilienceReduction, crit, CR_CRIT_TAKEN_MELEE); else - Unit::ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_RANGED); + Unit::ApplyResilience(victim, nullptr, &resilienceReduction, crit, CR_CRIT_TAKEN_RANGED); } + + resilienceReduction = damageInfo->damage - resilienceReduction; + damageInfo->damage -= resilienceReduction; + damageInfo->cleanDamage += resilienceReduction; break; } // Magical Attacks @@ -1255,30 +1285,33 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama if (crit) { damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT; - damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim); + damageInfo->damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damageInfo->damage, victim); } + int32 resilienceReduction = damageInfo->damage; if (CanApplyResilience()) - Unit::ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_SPELL); + Unit::ApplyResilience(victim, nullptr, &resilienceReduction, crit, CR_CRIT_TAKEN_SPELL); + + resilienceReduction = damageInfo->damage - resilienceReduction; + damageInfo->damage -= resilienceReduction; + damageInfo->cleanDamage += resilienceReduction; break; } default: break; } - // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations - sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage); - // Calculate absorb resist - if (damage > 0) + if (int32(damageInfo->damage) > 0) { - Unit::CalcAbsorbResist(this, victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo); - damage -= damageInfo->absorb + damageInfo->resist; + DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE); + Unit::CalcAbsorbResist(dmgInfo); + damageInfo->absorb = dmgInfo.GetAbsorb(); + damageInfo->resist = dmgInfo.GetResist(); + damage = dmgInfo.GetDamage(); } else - damage = 0; - - damageInfo->damage = std::max(damage, 0); + damageInfo->damage = 0; } void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss) @@ -1294,10 +1327,10 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss) if (!victim->IsAlive() || victim->IsInFlight() || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())) return; - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(damageInfo->SpellID); - if (spellProto == nullptr) + SpellInfo const* spellProto = damageInfo->spellInfo; + if (!spellProto) { - LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has wrong damageInfo->SpellID: %u", damageInfo->SpellID); + LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has wrong damageInfo"); return; } @@ -1504,7 +1537,11 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam { damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE; // Calculate absorb & resists - Unit::CalcAbsorbResist(this, damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist); + + DamageInfo dmgInfo(*damageInfo); + Unit::CalcAbsorbResist(dmgInfo); + damageInfo->absorb = dmgInfo.GetAbsorb(); + damageInfo->resist = dmgInfo.GetResist(); if (damageInfo->absorb) { @@ -1515,7 +1552,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam if (damageInfo->resist) damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST); - damageInfo->damage -= damageInfo->absorb + damageInfo->resist; + damageInfo->damage = dmgInfo.GetDamage(); } else // Impossible get negative result but.... damageInfo->damage = 0; @@ -1628,9 +1665,11 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) damage = this->SpellDamageBonusTaken(caster, i_spellProto, damage, SPELL_DIRECT_DAMAGE); uint32 absorb = 0; - uint32 resist = 0; - Unit::CalcAbsorbResist(victim, this, i_spellProto->GetSchoolMask(), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, i_spellProto); - damage -= absorb + resist; + + DamageInfo dmgInfo(victim, this, damage, i_spellProto, i_spellProto->GetSchoolMask(), SPELL_DIRECT_DAMAGE); + Unit::CalcAbsorbResist(dmgInfo); + absorb = dmgInfo.GetAbsorb(); + damage = dmgInfo.GetDamage(); Unit::DealDamageMods(this, damage, &absorb); @@ -1804,13 +1843,17 @@ float Unit::GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMa return victimResistance / (victimResistance + resistanceConstant); } -void Unit::CalcAbsorbResist(Unit* attacker, Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo, bool Splited) +void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) { + Unit* victim = dmgInfo.GetVictim(); + Unit* attacker = dmgInfo.GetAttacker(); + uint32 damage = dmgInfo.GetDamage(); + SpellSchoolMask schoolMask = dmgInfo.GetSchoolMask(); + SpellInfo const* spellInfo = dmgInfo.GetSpellInfo(); + if (!victim || !victim->IsAlive() || !damage) return; - DamageInfo dmgInfo = DamageInfo(attacker, victim, damage, spellInfo, schoolMask, damagetype); - // Magic damage, check for resists // Ignore spells that cant be resisted // Xinef: holy resistance exists for npcs @@ -2043,25 +2086,28 @@ void Unit::CalcAbsorbResist(Unit* attacker, Unit* victim, SpellSchoolMask school uint32 splitted_resist = 0; uint32 procAttacker = 0, procVictim = 0, procEx = PROC_EX_NORMAL_HIT; + DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, schoolMask, dmgInfo.GetDamageType()); if (caster->IsImmunedToDamageOrSchool(schoolMask)) { procEx |= PROC_EX_IMMUNE; - splitted_absorb = splitted; - splitted = 0; + splittedDmgInfo.AbsorbDamage(splitted); } else { + Unit::CalcAbsorbResist(splittedDmgInfo, true); Unit::DealDamageMods(caster, splitted, &splitted_absorb); - Unit::CalcAbsorbResist(attacker, caster, schoolMask, damagetype, splitted, &splitted_absorb, &splitted_resist, spellInfo, true); - splitted -= std::min(splitted_absorb, splitted); } + splitted_absorb = splittedDmgInfo.GetAbsorb(); + splitted_resist = splittedDmgInfo.GetResist(); + splitted = splittedDmgInfo.GetDamage(); + // create procs createProcFlags(spellInfo, BASE_ATTACK, false, procAttacker, procVictim); - caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted); + caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted, nullptr, -1, nullptr, &splittedDmgInfo); if (attacker) - attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted + splitted_absorb, schoolMask, splitted_absorb, 0, false, 0, false); + attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo(), splitted, schoolMask, splitted_absorb, splitted_resist, false, 0, false); CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); Unit::DealDamage(attacker, caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellInfo(), false); @@ -2111,50 +2157,51 @@ void Unit::CalcAbsorbResist(Unit* attacker, Unit* victim, SpellSchoolMask school uint32 splitted_resist = 0; uint32 procAttacker = 0, procVictim = 0, procEx = PROC_EX_NORMAL_HIT; + DamageInfo splittedDmgInfo(attacker, caster, splitted, spellInfo, splitSchoolMask, dmgInfo.GetDamageType()); if (caster->IsImmunedToDamageOrSchool(schoolMask)) { procEx |= PROC_EX_IMMUNE; - splitted_absorb = splitted; - splitted = 0; + splittedDmgInfo.AbsorbDamage(splitted); } else { + Unit::CalcAbsorbResist(splittedDmgInfo, true); Unit::DealDamageMods(caster, splitted, &splitted_absorb); - Unit::CalcAbsorbResist(attacker, caster, splitSchoolMask, damagetype, splitted, &splitted_absorb, &splitted_resist, spellInfo, true); - splitted -= std::min(splitted_absorb, splitted); } + splitted_absorb = splittedDmgInfo.GetAbsorb(); + splitted_resist = splittedDmgInfo.GetResist(); + splitted = splittedDmgInfo.GetDamage(); + // create procs createProcFlags(spellInfo, BASE_ATTACK, false, procAttacker, procVictim); caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted); if (attacker) - attacker->SendSpellNonMeleeDamageLog(caster, splitSpellInfo->Id, splitted + splitted_absorb, splitSchoolMask, splitted_absorb, 0, false, 0, false); + attacker->SendSpellNonMeleeDamageLog(caster, splitSpellInfo, splitted, splitSchoolMask, splitted_absorb, splitted_resist, false, 0, false); CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); Unit::DealDamage(attacker, caster, splitted, &cleanDamage, DIRECT_DAMAGE, splitSchoolMask, splitSpellInfo, false); } } - - *resist = dmgInfo.GetResist(); - *absorb = dmgInfo.GetAbsorb(); } -void Unit::CalcHealAbsorb(Unit const* victim, const SpellInfo* healSpell, uint32& healAmount, uint32& absorb) +void Unit::CalcHealAbsorb(HealInfo& healInfo) { - if (!healAmount) + if (!healInfo.GetHeal()) return; - int32 RemainingHeal = healAmount; + int32 const healing = static_cast(healInfo.GetHeal()); + int32 absorbAmount = 0; // Need remove expired auras after bool existExpired = false; // absorb without mana cost - AuraEffectList const& vHealAbsorb = victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_HEAL_ABSORB); - for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i) + AuraEffectList const& vHealAbsorb = healInfo.GetTarget()->GetAuraEffectsByType(SPELL_AURA_SCHOOL_HEAL_ABSORB); + for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && absorbAmount <= healing; ++i) { - if (!((*i)->GetMiscValue() & healSpell->SchoolMask)) + if (!((*i)->GetMiscValue() & healInfo.GetSpellInfo()->SchoolMask)) continue; // Max Amount can be absorbed by this aura @@ -2169,10 +2216,10 @@ void Unit::CalcHealAbsorb(Unit const* victim, const SpellInfo* healSpell, uint32 // currentAbsorb - damage can be absorbed by shield // If need absorb less damage - if (RemainingHeal < currentAbsorb) - currentAbsorb = RemainingHeal; + if (healing < currentAbsorb + absorbAmount) + currentAbsorb = healing - absorbAmount; - RemainingHeal -= currentAbsorb; + absorbAmount += currentAbsorb; // Reduce shield amount (*i)->SetAmount((*i)->GetAmount() - currentAbsorb); @@ -2190,16 +2237,16 @@ void Unit::CalcHealAbsorb(Unit const* victim, const SpellInfo* healSpell, uint32 ++i; if (auraEff->GetAmount() <= 0) { - uint32 removedAuras = victim->m_removedAurasCount; + uint32 removedAuras = healInfo.GetTarget()->m_removedAurasCount; auraEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL); - if (removedAuras + 1 < victim->m_removedAurasCount) + if (removedAuras + 1 < healInfo.GetTarget()->m_removedAurasCount) i = vHealAbsorb.begin(); } } } - absorb = RemainingHeal > 0 ? (healAmount - RemainingHeal) : healAmount; - healAmount = RemainingHeal; + if (absorbAmount > 0) + healInfo.AbsorbHeal(absorbAmount); } void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra) @@ -2239,7 +2286,10 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr //TriggerAurasProcOnEvent(damageInfo); DealMeleeDamage(&damageInfo, true); - ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType); + + DamageInfo dmgInfo(damageInfo); + ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, + damageInfo.attackType, nullptr, nullptr, -1, nullptr, &dmgInfo); if (GetTypeId() == TYPEID_PLAYER) LOG_DEBUG("entities.unit", "AttackerStateUpdate: (Player) %s attacked %s for %u dmg, absorbed %u, blocked %u, resisted %u.", @@ -5627,7 +5677,7 @@ void Unit::SendSpellNonMeleeReflectLog(SpellNonMeleeDamage* log, Unit* attacker) } data << log->target->GetPackGUID(); data << attacker->GetPackGUID(); - data << uint32(log->SpellID); + data << uint32(log->spellInfo->Id); data << uint32(damage); // damage amount int32 overkill = damage - log->target->GetHealth(); data << uint32(overkill > 0 ? overkill : 0); // overkill @@ -5655,7 +5705,7 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log) } data << log->target->GetPackGUID(); data << log->attacker->GetPackGUID(); - data << uint32(log->SpellID); + data << uint32(log->spellInfo->Id); data << uint32(damage); // damage amount int32 overkill = damage - log->target->GetHealth(); data << uint32(overkill > 0 ? overkill : 0); // overkill @@ -5670,10 +5720,10 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log) SendMessageToSet(&data, true); } -void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit) +void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit) { - SpellNonMeleeDamage log(this, target, SpellID, damageSchoolMask); - log.damage = Damage - AbsorbedDamage - Resist - Blocked; + SpellNonMeleeDamage log(this, target, spellInfo, damageSchoolMask); + log.damage = Damage; log.absorb = AbsorbedDamage; log.resist = Resist; log.physicalLog = PhysicalDamage; @@ -5684,15 +5734,15 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damag SendSpellNonMeleeDamageLog(&log); } -void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell) +void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpellInfo, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo) { // Not much to do if no flags are set. if (procAttacker) - ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell); + ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo); // Now go on with a victim's events'n'auras // Not much to do if no flags are set or there is no victim if (victim && victim->IsAlive() && procVictim) - victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell); + victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpellInfo, amount, procAura, procAuraEffectIndex, procSpell, damageInfo, healInfo); } void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo) @@ -10508,16 +10558,17 @@ void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 SendMessageToSet(&data, true); } -int32 Unit::HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical) +int32 Unit::HealBySpell(HealInfo& healInfo, bool critical) { - uint32 absorb = 0; + uint32 heal = healInfo.GetHeal(); + sScriptMgr->ModifyHealRecieved(this, healInfo.GetTarget(), heal); + healInfo.SetHeal(heal); + // calculate heal absorb and reduce healing - CalcHealAbsorb(victim, spellInfo, addHealth, absorb); + CalcHealAbsorb(healInfo); - sScriptMgr->ModifyHealRecieved(this, victim, addHealth); - - int32 gain = Unit::DealHeal(this, victim, addHealth); - SendHealSpellLog(victim, spellInfo->Id, addHealth, uint32(addHealth - gain), absorb, critical); + int32 gain = Unit::DealHeal(healInfo.GetHealer(), healInfo.GetTarget(), healInfo.GetHeal()); + SendHealSpellLog(healInfo.GetTarget(), healInfo.GetSpellInfo()->Id, healInfo.GetHeal(), uint32(healInfo.GetHeal() - gain), healInfo.GetAbsorb(), critical); return gain; } @@ -15302,7 +15353,7 @@ uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missC return procEx; } -void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell) +void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura, int8 procAuraEffectIndex, Spell const* procSpell, DamageInfo* damageInfo, HealInfo* healInfo) { // Player is loaded now - do not allow passive spell casts to proc if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading()) @@ -15397,9 +15448,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u Unit* actor = isVictim ? target : this; Unit* actionTarget = !isVictim ? target : this; - DamageInfo damageInfo = DamageInfo(actor, actionTarget, damage, procSpellInfo, procSpellInfo ? SpellSchoolMask(procSpellInfo->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL, SPELL_DIRECT_DAMAGE); - HealInfo healInfo = HealInfo(actor, actionTarget, damage, procSpellInfo, procSpellInfo ? SpellSchoolMask(procSpellInfo->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL); - ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, procSpell, &damageInfo, &healInfo, procAura, procAuraEffectIndex); + ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, procSpell, damageInfo, healInfo, procAura, procAuraEffectIndex); ProcTriggeredList procTriggered; // Fill procTriggered list diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index ab0d26963..4d57902d6 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -893,6 +893,7 @@ struct CleanDamage }; struct CalcDamageInfo; +struct SpellNonMeleeDamage; class DamageInfo { @@ -907,9 +908,11 @@ private: uint32 m_absorb; uint32 m_resist; uint32 m_block; + uint32 m_cleanDamage; public: - explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType); + explicit DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellInfo const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType, uint32 cleanDamage = 0); explicit DamageInfo(CalcDamageInfo& dmgInfo); + DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType); void ModifyDamage(int32 amount); void AbsorbDamage(uint32 amount); @@ -926,6 +929,8 @@ public: [[nodiscard]] uint32 GetAbsorb() const { return m_absorb; }; [[nodiscard]] uint32 GetResist() const { return m_resist; }; [[nodiscard]] uint32 GetBlock() const { return m_block; }; + + [[nodiscard]] uint32 GetUnmitigatedDamage() const; }; class HealInfo @@ -950,6 +955,11 @@ public: m_heal -= amount; } + void SetHeal(uint32 amount) + { + m_heal = amount; + } + [[nodiscard]] Unit* GetHealer() const { return m_healer; } [[nodiscard]] Unit* GetTarget() const { return m_target; } [[nodiscard]] uint32 GetHeal() const { return m_heal; } @@ -1020,21 +1030,21 @@ struct CalcDamageInfo // Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode struct SpellNonMeleeDamage { - SpellNonMeleeDamage(Unit* _attacker, Unit* _target, uint32 _SpellID, uint32 _schoolMask) - : target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask), + 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) {} - Unit* target; - Unit* attacker; - uint32 SpellID; + Unit* target; + Unit* attacker; + SpellInfo const* spellInfo; uint32 damage; uint32 overkill; uint32 schoolMask; uint32 absorb; uint32 resist; - bool physicalLog; - bool unused; + bool physicalLog; + bool unused; uint32 blocked; uint32 HitInfo; // Used for help @@ -1642,8 +1652,8 @@ public: static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr); static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth); - void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr); - void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr); + void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpellInfo = nullptr, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr); + void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpellInfo, uint32 damage, SpellInfo const* procAura = nullptr, int8 procAuraEffectIndex = -1, Spell const* procSpell = nullptr, DamageInfo* damageInfo = nullptr, HealInfo* healInfo = nullptr); void GetProcAurasTriggeredOnEvent(std::list& aurasTriggeringProc, std::list* procAuras, ProcEventInfo eventInfo); void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo); @@ -1791,7 +1801,7 @@ public: bool isInAccessiblePlaceFor(Creature const* c) const; void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false); - int32 HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical = false); + int32 HealBySpell(HealInfo& healInfo, bool critical = false); void SendEnergizeSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); void EnergizeBySpell(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); @@ -1820,7 +1830,7 @@ public: void SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount); void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log); void SendSpellNonMeleeReflectLog(SpellNonMeleeDamage* log, Unit* attacker); - void SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false); + void SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false); void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo); void SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo); void SendSpellDamageResist(Unit* target, uint32 spellId); @@ -2307,8 +2317,8 @@ public: // redefined in Creature static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = nullptr, uint8 effIndex = MAX_SPELL_EFFECTS); static uint32 CalcArmorReducedDamage(Unit const* attacker, Unit const* victim, const uint32 damage, SpellInfo const* spellInfo, uint8 attackerLevel = 0, WeaponAttackType attackType = MAX_ATTACK); - static void CalcAbsorbResist(Unit* attacker, Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo = nullptr, bool Splited = false); - static void CalcHealAbsorb(Unit const* victim, const SpellInfo* spellProto, uint32& healAmount, uint32& absorb); + static void CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited = false); + static void CalcHealAbsorb(HealInfo& healInfo); void UpdateSpeed(UnitMoveType mtype, bool forced); [[nodiscard]] float GetSpeed(UnitMoveType mtype) const; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 83e926bca..539d368c4 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -5933,7 +5933,8 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) if (caster) { int32 heal = caster->CountPctFromMaxHealth(10); - caster->HealBySpell(target, auraSpellInfo, heal); + HealInfo healInfo(caster, target, heal, auraSpellInfo, auraSpellInfo->GetSchoolMask()); + caster->HealBySpell(healInfo); if (int32 mana = caster->GetMaxPower(POWER_MANA)) { @@ -6272,8 +6273,6 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const } } - uint32 absorb = 0; - uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); // ignore non positive values (can be result apply spellmods to aura damage @@ -6333,23 +6332,33 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const if ((crit = roll_chance_f(GetCritChance()))) damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage, target); - int32 dmg = damage; - if (CanApplyResilience()) - Unit::ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL); - damage = dmg; - - Unit::CalcAbsorbResist(caster, target, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, GetSpellInfo()); - - LOG_DEBUG("spells.aura.effect", "PeriodicTick: %s attacked %s for %u dmg inflicted by %u abs is %u", - GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb); - Unit::DealDamageMods(target, damage, &absorb); - // Auras reducing damage from AOE spells if (GetSpellInfo()->Effects[GetEffIndex()].IsAreaAuraEffect() || GetSpellInfo()->Effects[GetEffIndex()].IsTargetingArea() || GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) // some persistent area auras have targets like A=53 B=28 { damage = target->CalculateAOEDamageReduction(damage, GetSpellInfo()->SchoolMask, caster); } + if (CanApplyResilience()) + { + int32 resilienceReduction = damage; + Unit::ApplyResilience(target, nullptr, &resilienceReduction, crit, CR_CRIT_TAKEN_SPELL); + + resilienceReduction = damage - resilienceReduction; + damage -= resilienceReduction; + cleanDamage.mitigated_damage += resilienceReduction; + } + + DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage); + Unit::CalcAbsorbResist(dmgInfo); + + uint32 absorb = dmgInfo.GetAbsorb(); + uint32 resist = dmgInfo.GetResist(); + damage = dmgInfo.GetDamage(); + + LOG_DEBUG("spells.aura.effect", "PeriodicTick: %s attacked %s for %u dmg inflicted by %u abs is %u", + GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb); + Unit::DealDamageMods(target, damage, &absorb); + // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; @@ -6357,7 +6366,6 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const if (absorb > 0) procEx |= PROC_EX_ABSORB; - damage = (damage <= absorb + resist) ? 0 : (damage - absorb - resist); if (damage) procVictim |= PROC_FLAG_TAKEN_DAMAGE; @@ -6370,7 +6378,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); // allow null caster to call this function - caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex()); + caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo); } void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const @@ -6388,8 +6396,6 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c caster->SpellHitResult(target, GetSpellInfo(), false) != SPELL_MISS_NONE) return; - uint32 absorb = 0; - uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); uint32 damage = std::max(GetAmount(), 0); @@ -6413,12 +6419,22 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c damage = damageReductedArmor; } - int32 dmg = damage; if (CanApplyResilience()) - Unit::ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL); - damage = dmg; + { + int32 resilienceReduction = damage; + Unit::ApplyResilience(target, nullptr, &resilienceReduction, crit, CR_CRIT_TAKEN_SPELL); - Unit::CalcAbsorbResist(caster, target, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, m_spellInfo); + resilienceReduction = damage - resilienceReduction; + damage -= resilienceReduction; + cleanDamage.mitigated_damage += resilienceReduction; + } + + DamageInfo dmgInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, cleanDamage.mitigated_damage); + Unit::CalcAbsorbResist(dmgInfo); + + uint32 absorb = dmgInfo.GetAbsorb(); + uint32 resist = dmgInfo.GetResist(); + damage = dmgInfo.GetDamage(); // Set trigger flag uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; @@ -6427,23 +6443,26 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c if (absorb > 0) procEx |= PROC_EX_ABSORB; - damage = (damage <= absorb + resist) ? 0 : (damage - absorb - resist); - if (damage) + if (dmgInfo.GetDamage()) procVictim |= PROC_FLAG_TAKEN_DAMAGE; - if (target->GetHealth() < damage) - damage = target->GetHealth(); + if (target->GetHealth() < dmgInfo.GetDamage()) + { + dmgInfo.ModifyDamage(dmgInfo.GetDamage() - target->GetHealth()); + } + + damage = dmgInfo.GetDamage(); LOG_DEBUG("spells.aura.effect", "PeriodicTick: %s health leech of %s for %u dmg inflicted by %u abs is %u", GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb); if (caster) - caster->SendSpellNonMeleeDamageLog(target, GetId(), damage + absorb + resist, GetSpellInfo()->GetSchoolMask(), absorb, resist, false, 0, crit); + caster->SendSpellNonMeleeDamageLog(target, GetSpellInfo(), damage, GetSpellInfo()->GetSchoolMask(), absorb, resist, false, 0, crit); int32 new_damage; new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); // allow null caster to call this function - caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex()); + caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo); if (!caster || !caster->IsAlive()) return; @@ -6453,7 +6472,8 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, 0.0f, GetBase()->GetStackAmount())); heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount())); - int32 gain = caster->HealBySpell(caster, GetSpellInfo(), heal); + HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); + int32 gain = caster->HealBySpell(healInfo); caster->getHostileRefMgr().threatAssist(caster, gain * 0.5f, GetSpellInfo()); } @@ -6482,7 +6502,8 @@ void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) damage = int32(damage * gainMultiplier); - caster->HealBySpell(target, GetSpellInfo(), damage); + HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); + caster->HealBySpell(healInfo); } void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const @@ -6579,16 +6600,17 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const LOG_DEBUG("spells.aura.effect", "PeriodicTick: %s heal of %s for %u health inflicted by %u", GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId()); - uint32 absorb = 0; + uint32 heal = uint32(damage); // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, heal); - Unit::CalcHealAbsorb(target, GetSpellInfo(), heal, absorb); - int32 gain = Unit::DealHeal(caster, target, heal); + HealInfo healInfo(caster, target, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); + Unit::CalcHealAbsorb(healInfo); + int32 gain = Unit::DealHeal(caster, target, healInfo.GetHeal()); - SpellPeriodicAuraLogInfo pInfo(this, heal, heal - gain, absorb, 0, 0.0f, crit); + SpellPeriodicAuraLogInfo pInfo(this, healInfo.GetHeal(), healInfo.GetHeal() - gain, healInfo.GetAbsorb(), 0, 0.0f, crit); target->SendPeriodicAuraLog(&pInfo); if (caster) @@ -6610,20 +6632,20 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const uint32 absorb2 = 0; Unit::DealDamageMods(caster, manaPerSecond, &absorb2); - CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); + CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); Unit::DealDamage(caster, caster, manaPerSecond, &cleanDamage, SELF_DAMAGE, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); } uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT; - if (absorb > 0) + if (healInfo.GetAbsorb() > 0) procEx |= PROC_EX_ABSORB; // ignore item heals if (!haveCastItem && GetAuraType() != SPELL_AURA_OBS_MOD_HEALTH) // xinef: dont allow obs_mod_health to proc spells, this is passive regeneration and not hot // xinef: allow null caster to proc - caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex()); + caster->ProcDamageAndSpell(target, caster ? procAttacker : 0, procVictim, procEx, heal, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const @@ -6793,7 +6815,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con SpellInfo const* spellProto = GetSpellInfo(); // maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG - SpellNonMeleeDamage damageInfo(caster, target, spellProto->Id, spellProto->SchoolMask); + SpellNonMeleeDamage damageInfo(caster, target, spellProto, spellProto->SchoolMask); // no SpellDamageBonus for burn mana caster->CalculateSpellDamageTaken(&damageInfo, int32(gain * dmgMultiplier), spellProto); @@ -6809,7 +6831,9 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con procVictim |= PROC_FLAG_TAKEN_DAMAGE; caster->DealSpellDamage(&damageInfo, true); - caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex()); + + DamageInfo dmgInfo(damageInfo, DOT); + caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto, nullptr, GetEffIndex(), nullptr, &dmgInfo); } void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) @@ -6854,7 +6878,7 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv { Unit* target = aurApp->GetTarget(); Unit* triggerTarget = eventInfo.GetProcTarget(); - SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetSpellInfo()->SchoolMask); + SpellNonMeleeDamage damageInfo(target, triggerTarget, GetSpellInfo(), GetSpellInfo()->SchoolMask); uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE); damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellInfo()); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 898cc31cb..c4de3896a 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2571,6 +2571,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) else procEx |= PROC_EX_NORMAL_HIT; + HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask()); + // Xinef: override with forced crit, only visual result if (GetSpellValue()->ForcedCritResult) { @@ -2578,7 +2580,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) procEx |= PROC_EX_CRITICAL_HIT; } - int32 gain = caster->HealBySpell(unitTarget, m_spellInfo, addhealth, crit); + int32 gain = caster->HealBySpell(healInfo, crit); unitTarget->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, m_spellInfo); m_healing = gain; @@ -2588,13 +2590,14 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) - caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell, m_triggeredByAuraEffectIndex, this); + caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell, + m_triggeredByAuraEffectIndex, this, nullptr, &healInfo); } // Do damage and triggers else if (m_damage > 0) { // Fill base damage struct (unitTarget - is real spell target) - SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask); + SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask); // Add bonuses and fill damageInfo struct // Dancing Rune Weapon... @@ -2641,7 +2644,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL); healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL); - m_caster->HealBySpell(m_caster, m_spellInfo, uint32(healthGain)); + HealInfo healInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellInfo->GetSchoolMask()); + m_caster->HealBySpell(healInfo); } } @@ -2662,7 +2666,10 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) { - caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell, m_triggeredByAuraEffectIndex, this); + DamageInfo dmgInfo(damageInfo, SPELL_DIRECT_DAMAGE); + caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell, + m_triggeredByAuraEffectIndex, this, &dmgInfo); + if (caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 && m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx); @@ -2674,12 +2681,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) else { // Fill base damage struct (unitTarget - is real spell target) - SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask); + SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask); procEx |= createProcExtendMask(&damageInfo, missInfo); // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger) { - caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell, m_triggeredByAuraEffectIndex, this); + DamageInfo dmgInfo(damageInfo, NODAMAGE); + caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell, + m_triggeredByAuraEffectIndex, this, &dmgInfo); + // Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also // Xinef: ofc count only spells that HIT the target, little hack used to fool the system if ((procEx & PROC_EX_NORMAL_HIT || procEx & PROC_EX_CRITICAL_HIT) && caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 && diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index ff2c0b7f5..2c81b6141 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -302,14 +302,21 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) if (!unitTarget || !unitTarget->IsAlive()) return; - uint32 absorb = 0; - uint32 resist = 0; - - Unit::CalcAbsorbResist(m_caster, unitTarget, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, m_spellInfo); - - m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage + absorb + resist, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false); - if (unitTarget->GetTypeId() == TYPEID_PLAYER) + if (unitTarget->IsPlayer()) unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage); + else + { + DamageInfo dmgInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE); + + uint32 absorb = dmgInfo.GetAbsorb(); + uint32 resist = dmgInfo.GetResist(); + uint32 envDamage = dmgInfo.GetDamage(); + + Unit::DealDamageMods(unitTarget, envDamage, &absorb); + damage = envDamage; + + m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false); + } } void Spell::EffectSchoolDMG(SpellEffIndex effIndex) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index ea913c3bf..99e40eaaa 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3201,7 +3201,6 @@ void SpellMgr::LoadSpellCustomAttr() spellInfo->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR; break; case 64422: // Sonic Screech (Auriaya) - case 13877: // Blade Flurry (Rogue Spell) should ignore armor and share damage to 2nd mob spellInfo->AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE; spellInfo->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR; break; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index cf5089ba3..23df499d1 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -850,10 +850,15 @@ public: uint32 resist = 0; CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); int32 dmg = urand(2925, 3075) * (caster->GetMap()->GetDifficulty() - 1); + uint32 damage = dmg; + int32 resilienceReduction = damage; if (caster->CanApplyResilience()) Unit::ApplyResilience(plr, nullptr, &dmg, false, CR_CRIT_TAKEN_SPELL); - uint32 damage = dmg; - Unit::CalcAbsorbResist(caster, plr, GetSpellInfo()->GetSchoolMask(), DOT, damage, &absorb, &resist, GetSpellInfo()); + resilienceReduction = damage - resilienceReduction; + damage -= resilienceReduction; + uint32 mitigated_damage = resilienceReduction; + DamageInfo dmgInfo(caster, plr, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, mitigated_damage); + Unit::CalcAbsorbResist(dmgInfo); Unit::DealDamageMods(plr, damage, &absorb); int32 overkill = damage - plr->GetHealth(); if (overkill < 0) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index e75440acc..f32cff7a4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -855,7 +855,7 @@ public: uint32 damage = uint32( (GetEffectValue() / _targetCount) * (1.0f - ResistFactor) ); - SpellNonMeleeDamage damageInfo(GetCaster(), GetHitUnit(), GetSpellInfo()->Id, GetSpellInfo()->SchoolMask); + SpellNonMeleeDamage damageInfo(GetCaster(), GetHitUnit(), GetSpellInfo(), GetSpellInfo()->SchoolMask); damageInfo.damage = damage; GetCaster()->SendSpellNonMeleeDamageLog(&damageInfo); GetCaster()->DealSpellDamage(&damageInfo, false); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 290cae7ec..876bb57b9 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -414,7 +414,7 @@ public: bool CheckProc(ProcEventInfo& eventInfo) { - SpellInfo const* spellInfo = eventInfo.GetDamageInfo()->GetSpellInfo(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); if (!spellInfo) return false; diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index dddc6074d..b5eeb0ada 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -146,9 +146,7 @@ public: Unit* procTarget = ObjectAccessor::GetUnit(*GetTarget(), _procTargetGUID); if (procTarget && eventInfo.GetDamageInfo()) { - int32 damage = eventInfo.GetDamageInfo()->GetDamage(); - // Xinef: Include AOE Damage Reduction auras - damage = procTarget->CalculateAOEDamageReduction(damage, SPELL_SCHOOL_MASK_NORMAL, GetTarget()); + int32 damage = eventInfo.GetDamageInfo()->GetUnmitigatedDamage(); CustomSpellValues values; values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 16cb93f3e..30bc98a12 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -818,8 +818,11 @@ public: void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - int32 damage = eventInfo.GetDamageInfo()->GetDamage(); - GetTarget()->CastCustomSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK, &damage, 0, 0, true, nullptr, aurEff); + if (eventInfo.GetDamageInfo()) + { + int32 damage = eventInfo.GetDamageInfo()->GetUnmitigatedDamage(); + GetTarget()->CastCustomSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK, &damage, 0, 0, true, nullptr, aurEff); + } } void Register() override