aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2018-01-13 06:45:21 -0300
committerariel- <ariel-@users.noreply.github.com>2018-01-13 06:45:21 -0300
commitcb9e72e521d3cc415dd15bf6912c87f89e41b92a (patch)
treebe9e692f0ddf9f080f923c7396de19e4ca869c6f /src/server/game
parent1c60af632888433b29a27bee76e82e96632d4096 (diff)
Core/Auras: removed caster dependency from core
- Decoupled Unit logic: split of spell critical chance into done (caster bonuses) and taken (target bonuses), this allows to precalculate caster bonuses on aura apply and then check victim's auras on damage/healing calc - Made static a bunch of methods (they no longer have this pointer because they are now called from periodic handlers which may or may not have an active caster in world) - Simplified all AuraEffect bonuses into AuraEffect::_amount, no more duplicated code - Critical chance and whether or not caster is player owned unit (for resilience calcs) is now saved one level upper, on Aura itself (it's impossible as of 3.3.5 to have different effects with different critical chances) - Minor cleanup of SPELL_DAMAGE_CLASS_NONE and Arcane Potency (#18813) crit handling Closes #19876
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp6
-rw-r--r--src/server/game/Entities/Player/Player.cpp18
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp955
-rw-r--r--src/server/game/Entities/Unit/Unit.h43
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp360
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h20
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp120
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h26
-rw-r--r--src/server/game/Spells/Spell.cpp23
-rw-r--r--src/server/game/Spells/SpellEffects.cpp50
-rw-r--r--src/server/game/Spells/SpellMgr.cpp23
12 files changed, 855 insertions, 791 deletions
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index abd82bf7f4a..29c275a0922 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -1177,6 +1177,8 @@ void Pet::_LoadAuras(uint32 timediff)
int32 maxduration = fields[11].GetInt32();
int32 remaintime = fields[12].GetInt32();
uint8 remaincharges = fields[13].GetUInt8();
+ float critChance = fields[14].GetFloat();
+ bool applyResilience = fields[15].GetBool();
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
if (!spellInfo)
@@ -1210,7 +1212,7 @@ void Pet::_LoadAuras(uint32 timediff)
aura->Remove();
continue;
}
- aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]);
+ aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, critChance, applyResilience, &damage[0]);
aura->ApplyForTargets();
TC_LOG_DEBUG("entities.pet", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask);
}
@@ -1275,6 +1277,8 @@ void Pet::_SaveAuras(SQLTransaction& trans)
stmt->setInt32(index++, itr->second->GetMaxDuration());
stmt->setInt32(index++, itr->second->GetDuration());
stmt->setUInt8(index++, itr->second->GetCharges());
+ stmt->setFloat(index++, itr->second->GetCritChance());
+ stmt->setBool (index++, itr->second->CanApplyResilience());
trans->Append(stmt);
}
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 862f36b8dfc..b98daee4fd3 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -771,7 +771,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
case DAMAGE_SLIME:
{
DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, BASE_ATTACK);
- CalcAbsorbResist(dmgInfo);
+ Unit::CalcAbsorbResist(dmgInfo);
absorb = dmgInfo.GetAbsorb();
resist = dmgInfo.GetResist();
damage = dmgInfo.GetDamage();
@@ -781,7 +781,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
break;
}
- DealDamageMods(this, damage, &absorb);
+ Unit::DealDamageMods(this, damage, &absorb);
WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21));
data << uint64(GetGUID());
@@ -791,7 +791,7 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
data << uint32(resist);
SendMessageToSet(&data, true);
- uint32 final_damage = DealDamage(this, damage, nullptr, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
+ uint32 final_damage = Unit::DealDamage(this, this, damage, nullptr, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
if (!IsAlive())
{
@@ -17769,8 +17769,8 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff)
/* 0 1 2 3 4 5 6 7 8 9 10
QueryResult* result = CharacterDatabase.PQuery("SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2,
- 11 12 13
- maxDuration, remainTime, remainCharges FROM character_aura WHERE guid = '%u'", GetGUID().GetCounter());
+ 11 12 13 14 15
+ maxDuration, remainTime, remainCharges, critChance, applyResilience FROM character_aura WHERE guid = '%u'", GetGUID().GetCounter());
*/
if (result)
@@ -17794,6 +17794,8 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff)
int32 maxduration = fields[11].GetInt32();
int32 remaintime = fields[12].GetInt32();
uint8 remaincharges = fields[13].GetUInt8();
+ float critChance = fields[14].GetFloat();
+ bool applyResilience = fields[15].GetBool();
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
if (!spellInfo)
@@ -17831,7 +17833,7 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff)
continue;
}
- aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]);
+ aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, critChance, applyResilience, &damage[0]);
aura->ApplyForTargets();
TC_LOG_DEBUG("entities.player", "Player::_LoadAuras: Added aura (SpellID: %u, EffectMask: %u) to player '%s (%s)",
spellInfo->Id, effmask, GetName().c_str(), GetGUID().ToString().c_str());
@@ -19517,7 +19519,9 @@ void Player::_SaveAuras(SQLTransaction& trans)
stmt->setInt32(index++, baseDamage[2]);
stmt->setInt32(index++, itr->second->GetMaxDuration());
stmt->setInt32(index++, itr->second->GetDuration());
- stmt->setUInt8(index, itr->second->GetCharges());
+ stmt->setUInt8(index++, itr->second->GetCharges());
+ stmt->setFloat(index++, itr->second->GetCritChance());
+ stmt->setBool (index++, itr->second->CanApplyResilience());
trans->Append(stmt);
}
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index d74b36c1e84..271cd465709 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1594,6 +1594,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 GetBaseSpellPowerBonus() const { return m_baseSpellPower; }
int32 GetSpellPenetrationItemMod() const { return m_spellPenetrationItemMod; }
+ bool CanApplyResilience() const override { return true; }
+
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const;
void UpdateBlockPercentage();
void UpdateCritPercentage(WeaponAttackType attType);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 811be1e2076..5020baa928f 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -625,7 +625,7 @@ bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) cons
|| HasBreakableByDamageAuraType(SPELL_AURA_TRANSFORM, excludeAura));
}
-void Unit::DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) const
+/*static*/ void Unit::DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb)
{
if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
{
@@ -635,20 +635,20 @@ void Unit::DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) co
}
}
-uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
+/*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
{
uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
if (victim->IsAIEnabled)
- victim->GetAI()->DamageTaken(this, damage);
+ victim->GetAI()->DamageTaken(attacker, damage);
- if (IsAIEnabled)
- GetAI()->DamageDealt(victim, damage, damagetype);
+ if (attacker && attacker->IsAIEnabled)
+ attacker->GetAI()->DamageDealt(victim, damage, damagetype);
// Hook for OnDamage Event
- sScriptMgr->OnDamage(this, victim, damage);
+ sScriptMgr->OnDamage(attacker, victim, damage);
- if (victim->GetTypeId() == TYPEID_PLAYER && this != victim)
+ if (victim->GetTypeId() == TYPEID_PLAYER && attacker != victim)
{
// Signal to pets that their owner was attacked - except when DOT.
if (damagetype != DOT)
@@ -656,7 +656,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
for (Unit* controlled : victim->m_Controlled)
if (Creature* cControlled = controlled->ToCreature())
if (cControlled->IsAIEnabled)
- cControlled->AI()->OwnerAttackedBy(this);
+ cControlled->AI()->OwnerAttackedBy(attacker);
}
if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD))
@@ -674,16 +674,20 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
else
victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, 0);
- // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots)
- if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
- if (victim != this && victim->GetTypeId() == TYPEID_PLAYER)
- if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
- if (spell->getState() == SPELL_STATE_PREPARING)
- {
- uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
- if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0)
- victim->InterruptNonMeleeSpells(false);
- }
+ // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots)
+ if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
+ {
+ if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
+ if (spell->getState() == SPELL_STATE_PREPARING)
+ {
+ uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
+ if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0)
+ victim->InterruptNonMeleeSpells(false);
+ }
+ }
+ }
// 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
@@ -706,13 +710,13 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
uint32 share = CalculatePct(damage, (*i)->GetAmount());
/// @todo check packets if damage is done by victim, or by attacker of victim
- DealDamageMods(shareDamageTarget, share, nullptr);
- DealDamage(shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false);
+ Unit::DealDamageMods(shareDamageTarget, share, nullptr);
+ Unit::DealDamage(attacker, shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false);
}
}
// Rage from Damage made (only from direct weapon damage)
- if (cleanDamage && damagetype == DIRECT_DAMAGE && this != victim && getPowerType() == POWER_RAGE)
+ if (attacker && cleanDamage && damagetype == DIRECT_DAMAGE && attacker != victim && attacker->getPowerType() == POWER_RAGE)
{
uint32 weaponSpeedHitFactor;
@@ -721,11 +725,11 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
case BASE_ATTACK:
case OFF_ATTACK:
{
- weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType) / 1000.0f * (cleanDamage->attackType == BASE_ATTACK ? 3.5f : 1.75f));
+ weaponSpeedHitFactor = uint32(attacker->GetAttackTime(cleanDamage->attackType) / 1000.0f * (cleanDamage->attackType == BASE_ATTACK ? 3.5f : 1.75f));
if (cleanDamage->hitOutCome == MELEE_HIT_CRIT)
weaponSpeedHitFactor *= 2;
- RewardRage(rage_damage, weaponSpeedHitFactor, true);
+ attacker->RewardRage(rage_damage, weaponSpeedHitFactor, true);
break;
}
case RANGED_ATTACK:
@@ -744,18 +748,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
return 0;
}
- TC_LOG_DEBUG("entities.unit", "DealDamageStart");
-
uint32 health = victim->GetHealth();
- TC_LOG_DEBUG("entities.unit", "%s dealt %u damage to %s", GetGUID().ToString().c_str(), damage, victim->GetGUID().ToString().c_str());
// duel ends when player has 1 or less hp
bool duel_hasEnded = false;
bool duel_wasMounted = false;
if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health-1))
{
+ if (!attacker)
+ return 0;
+
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
- if (victim->ToPlayer()->duel->opponent == this || victim->ToPlayer()->duel->opponent->GetGUID() == GetOwnerGUID())
+ if (victim->ToPlayer()->duel->opponent == attacker || victim->ToPlayer()->duel->opponent->GetGUID() == attacker->GetOwnerGUID())
damage = health - 1;
duel_hasEnded = true;
@@ -766,8 +770,11 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
if (victimRider && victimRider->duel && victimRider->duel->isMounted)
{
+ if (!attacker)
+ return 0;
+
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
- if (victimRider->duel->opponent == this || victimRider->duel->opponent->GetGUID() == GetCharmerGUID())
+ if (victimRider->duel->opponent == attacker || victimRider->duel->opponent->GetGUID() == attacker->GetCharmerGUID())
damage = health - 1;
duel_wasMounted = true;
@@ -775,17 +782,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
}
}
- if (GetTypeId() == TYPEID_PLAYER && this != victim)
+ if (attacker && attacker != victim)
{
- Player* killer = ToPlayer();
-
- // in bg, count dmg if victim is also a player
- if (victim->GetTypeId() == TYPEID_PLAYER)
- if (Battleground* bg = killer->GetBattleground())
- bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
+ if (Player* killer = attacker->ToPlayer())
+ {
+ // in bg, count dmg if victim is also a player
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ if (Battleground* bg = killer->GetBattleground())
+ bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
- killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, health > damage ? damage : health, 0, victim);
- killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
+ killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, health > damage ? damage : health, 0, victim);
+ killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
+ }
}
if (victim->GetTypeId() == TYPEID_PLAYER)
@@ -793,25 +801,21 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
else if (!victim->IsControlledByPlayer() || victim->IsVehicle())
{
if (!victim->ToCreature()->hasLootRecipient())
- victim->ToCreature()->SetLootRecipient(this);
+ victim->ToCreature()->SetLootRecipient(attacker);
- if (IsControlledByPlayer() || (ToTempSummon() && ToTempSummon()->GetSummoner() && ToTempSummon()->GetSummoner()->GetTypeId() == TYPEID_PLAYER))
+ if (!attacker || attacker->IsControlledByPlayer() || (attacker->ToTempSummon() && attacker->ToTempSummon()->GetSummoner() && attacker->ToTempSummon()->GetSummoner()->GetTypeId() == TYPEID_PLAYER))
victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
}
if (health <= damage)
{
- TC_LOG_DEBUG("entities.unit", "DealDamage: victim just died");
-
- if (victim->GetTypeId() == TYPEID_PLAYER && victim != this)
+ if (victim->GetTypeId() == TYPEID_PLAYER && victim != attacker)
victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health);
- Kill(victim, durabilityLoss);
+ Unit::Kill(attacker, victim, durabilityLoss);
}
else
{
- TC_LOG_DEBUG("entities.unit", "DealDamageAlive");
-
if (victim->GetTypeId() == TYPEID_PLAYER)
victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage);
@@ -826,7 +830,8 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
if (damagetype != DOT && damage > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD)))
victim->ToCreature()->SetLastDamagedTime(GameTime::GetGameTime() + MAX_AGGRO_RESET_TIME);
- victim->GetThreatManager().AddThreat(this, float(damage), spellProto);
+ if (attacker)
+ victim->GetThreatManager().AddThreat(attacker, float(damage), spellProto);
}
else // victim is a player
{
@@ -839,29 +844,31 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
}
// Rage from damage received
- if (this != victim && victim->getPowerType() == POWER_RAGE)
+ if (attacker != victim && victim->getPowerType() == POWER_RAGE)
{
rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
victim->RewardRage(rage_damage, 0, false);
}
- if (GetTypeId() == TYPEID_PLAYER)
+ if (attacker && attacker->GetTypeId() == TYPEID_PLAYER)
{
// random durability for items (HIT DONE)
if (roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
{
EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1));
- ToPlayer()->DurabilityPointLossForEquipSlot(slot);
+ attacker->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
}
}
if (damagetype != NODAMAGE && damage)
{
- if (victim != this && victim->GetTypeId() == TYPEID_PLAYER && // does not support creature push_back
+ if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER && // does not support creature push_back
(!spellProto || !(spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE) || spellProto->HasAttribute(SPELL_ATTR3_TREAT_AS_PERIODIC))))
{
if (damagetype != DOT)
+ {
if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
+ {
if (spell->getState() == SPELL_STATE_PREPARING)
{
uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
@@ -870,14 +877,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
else if (interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK)
spell->Delayed();
}
+ }
+ }
if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
+ {
if (spell->getState() == SPELL_STATE_CASTING)
{
uint32 channelInterruptFlags = spell->m_spellInfo->ChannelInterruptFlags;
if (((channelInterruptFlags & CHANNEL_FLAG_DELAY) != 0) && (damagetype != DOT))
spell->DelayedChannel();
}
+ }
}
}
@@ -901,8 +912,6 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
}
}
- TC_LOG_DEBUG("entities.unit", "DealDamageEnd returned %d damage", damage);
-
return damage;
}
@@ -970,8 +979,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
// Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage.
if (!spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
{
- if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
- damage = CalcArmorReducedDamage(victim, damage, spellInfo, attackType);
+ if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo))
+ damage = Unit::CalcArmorReducedDamage(this, victim, damage, spellInfo, attackType);
bool blocked = false;
// Per-school calc
@@ -1035,10 +1044,8 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
damage -= damageInfo->blocked;
}
- if (attackType != RANGED_ATTACK)
- ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_MELEE);
- else
- ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_RANGED);
+ if (CanApplyResilience())
+ Unit::ApplyResilience(victim, nullptr, &damage, crit, (attackType == RANGED_ATTACK ? CR_CRIT_TAKEN_RANGED : CR_CRIT_TAKEN_MELEE));
break;
}
// Magical Attacks
@@ -1049,10 +1056,11 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
if (crit)
{
damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
- damage = SpellCriticalDamageBonus(spellInfo, damage, victim);
+ damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim);
}
- ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_SPELL);
+ if (CanApplyResilience())
+ Unit::ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_SPELL);
break;
}
default:
@@ -1069,7 +1077,7 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
damageInfo->damage = damage;
DamageInfo dmgInfo(*damageInfo, SPELL_DIRECT_DAMAGE, BASE_ATTACK, PROC_HIT_NONE);
- CalcAbsorbResist(dmgInfo);
+ Unit::CalcAbsorbResist(dmgInfo);
damageInfo->absorb = dmgInfo.GetAbsorb();
damageInfo->resist = dmgInfo.GetResist();
@@ -1103,7 +1111,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss)
// Call default DealDamage
CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
+ Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
}
/// @todo for melee need create structure as in
@@ -1167,9 +1175,9 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
sScriptMgr->ModifyMeleeDamage(damageInfo->target, damageInfo->attacker, damage);
// Calculate armor reduction
- if (IsDamageReducedByArmor((SpellSchoolMask)(damageInfo->damageSchoolMask)))
+ if (Unit::IsDamageReducedByArmor((SpellSchoolMask)(damageInfo->damageSchoolMask)))
{
- damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage, nullptr, damageInfo->attackType);
+ damageInfo->damage = Unit::CalcArmorReducedDamage(damageInfo->attacker, damageInfo->target, damage, nullptr, damageInfo->attackType);
damageInfo->cleanDamage += damage - damageInfo->damage;
}
else
@@ -1278,7 +1286,8 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
int32 resilienceReduction = damageInfo->damage;
// attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here
- ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE);
+ if (CanApplyResilience())
+ Unit::ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE);
resilienceReduction = damageInfo->damage - resilienceReduction;
damageInfo->damage -= resilienceReduction;
damageInfo->cleanDamage += resilienceReduction;
@@ -1289,7 +1298,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE;
// Calculate absorb & resists
DamageInfo dmgInfo(*damageInfo);
- CalcAbsorbResist(dmgInfo);
+ Unit::CalcAbsorbResist(dmgInfo);
damageInfo->absorb = dmgInfo.GetAbsorb();
damageInfo->resist = dmgInfo.GetResist();
@@ -1353,7 +1362,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
// Call default DealDamage
CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, damageInfo->attackType, damageInfo->hitOutCome);
- DealDamage(victim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), nullptr, durabilityLoss);
+ Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), nullptr, durabilityLoss);
// If this is a creature and it attacks from behind it has a probability to daze it's victim
if ((damageInfo->hitOutCome == MELEE_HIT_CRIT || damageInfo->hitOutCome == MELEE_HIT_CRUSHING || damageInfo->hitOutCome == MELEE_HIT_NORMAL || damageInfo->hitOutCome == MELEE_HIT_GLANCING) &&
@@ -1412,12 +1421,12 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
uint32 damage = aurEff->GetAmount();
if (Unit* caster = aurEff->GetCaster())
{
- damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE, { });
damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE);
}
// No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that
- victim->DealDamageMods(this, damage, nullptr);
+ Unit::DealDamageMods(this, damage, nullptr);
/// @todo Move this to a packet handler
WorldPacket data(SMSG_SPELLDAMAGESHIELD, 8 + 8 + 4 + 4 + 4 + 4 + 4);
@@ -1430,7 +1439,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
data << uint32(spellInfo->SchoolMask);
victim->SendMessageToSet(&data, true);
- victim->DealDamage(this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
+ Unit::DealDamage(victim, this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
}
}
}
@@ -1443,7 +1452,7 @@ void Unit::HandleEmoteCommand(uint32 anim_id)
SendMessageToSet(&data, true);
}
-bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/, int8 effIndex /*= -1*/)
+/*static*/ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/, int8 effIndex /*= -1*/)
{
// only physical spells damage gets reduced by armor
if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
@@ -1466,72 +1475,75 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s
return true;
}
-uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType) const
+/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, uint8 attackerLevel /*= 0*/, WeaponAttackType attackType /*= MAX_ATTACK*/)
{
float armor = float(victim->GetArmor());
// Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
- armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL);
-
- if (spellInfo)
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
-
- AuraEffectList const& resIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
- for (AuraEffectList::const_iterator j = resIgnoreAurasAb.begin(); j != resIgnoreAurasAb.end(); ++j)
+ if (attacker)
{
- if ((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && (*j)->IsAffectedOnSpell(spellInfo))
- armor = std::floor(AddPct(armor, -(*j)->GetAmount()));
- }
+ armor += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL);
- AuraEffectList const& resIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
- for (AuraEffectList::const_iterator j = resIgnoreAuras.begin(); j != resIgnoreAuras.end(); ++j)
- {
- if ((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
- armor = std::floor(AddPct(armor, -(*j)->GetAmount()));
- }
+ if (spellInfo)
+ if (Player* modOwner = attacker->GetSpellModOwner())
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
- // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc.
- if (GetTypeId() == TYPEID_PLAYER)
- {
- float arpPct = ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION);
+ AuraEffectList const& resIgnoreAurasAb = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
+ for (AuraEffect const* aurEff : resIgnoreAurasAb)
+ {
+ if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && aurEff->IsAffectedOnSpell(spellInfo))
+ armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
+ }
- Item const* weapon = ToPlayer()->GetWeaponForAttack(attackType, true);
- arpPct += GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool
+ AuraEffectList const& resIgnoreAuras = attacker->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
+ for (AuraEffect const* aurEff : resIgnoreAuras)
{
- return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon);
- });
+ if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
+ armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
+ }
- // no more than 100%
- RoundToInterval(arpPct, 0.f, 100.f);
+ // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc.
+ if (attacker->GetTypeId() == TYPEID_PLAYER)
+ {
+ float arpPct = attacker->ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION);
- float maxArmorPen = 0.f;
- if (victim->getLevel() < 60)
- maxArmorPen = float(400 + 85 * victim->getLevel());
- else
- maxArmorPen = 400 + 85 * victim->getLevel() + 4.5f * 85 * (victim->getLevel() - 59);
+ Item const* weapon = attacker->ToPlayer()->GetWeaponForAttack(attackType, true);
+ arpPct += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool
+ {
+ return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon);
+ });
- // Cap armor penetration to this number
- maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor);
- // Figure out how much armor do we ignore
- armor -= CalculatePct(maxArmorPen, arpPct);
+ // no more than 100%
+ RoundToInterval(arpPct, 0.f, 100.f);
+
+ float maxArmorPen = 0.f;
+ if (victim->getLevel() < 60)
+ maxArmorPen = float(400 + 85 * victim->getLevel());
+ else
+ maxArmorPen = 400 + 85 * victim->getLevel() + 4.5f * 85 * (victim->getLevel() - 59);
+
+ // Cap armor penetration to this number
+ maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor);
+ // Figure out how much armor do we ignore
+ armor -= CalculatePct(maxArmorPen, arpPct);
+ }
}
if (armor < 0.0f)
armor = 0.0f;
- float levelModifier = getLevel();
- if (levelModifier > 59)
- levelModifier = levelModifier + 4.5f * (levelModifier - 59);
+ float levelModifier = attacker ? attacker->getLevel() : attackerLevel;
+ if (levelModifier > 59.f)
+ levelModifier = levelModifier + 4.5f * (levelModifier - 59.f);
- float damageReduction = 0.1f * armor / (8.5f * levelModifier + 40);
+ float damageReduction = 0.1f * armor / (8.5f * levelModifier + 40.f);
damageReduction /= (1.0f + damageReduction);
RoundToInterval(damageReduction, 0.f, 0.75f);
return std::max<uint32>(damage * (1.0f - damageReduction), 1);
}
-uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const
+/*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo)
{
// Magic damage, check for resists
if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
@@ -1552,8 +1564,7 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas
return 0;
}
- float const averageResist = CalculateAverageResistReduction(schoolMask, victim, spellInfo);
-
+ float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
float discreteResistProbability[11] = { };
if (averageResist <= 0.1f)
{
@@ -1579,14 +1590,17 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas
if (damageResisted > 0.0f) // if any damage was resisted
{
int32 ignoredResistance = 0;
- ignoredResistance += GetTotalAuraModifier(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, [schoolMask, spellInfo](AuraEffect const* aurEff) -> bool
+ if (attacker)
{
- if ((aurEff->GetMiscValue() & schoolMask) && aurEff->IsAffectedOnSpell(spellInfo))
- return true;
- return false;
- });
+ ignoredResistance += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, [schoolMask, spellInfo](AuraEffect const* aurEff) -> bool
+ {
+ if ((aurEff->GetMiscValue() & schoolMask) && aurEff->IsAffectedOnSpell(spellInfo))
+ return true;
+ return false;
+ });
- ignoredResistance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
+ ignoredResistance += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
+ }
ignoredResistance = std::min<int32>(ignoredResistance, 100);
ApplyPct(damageResisted, 100 - ignoredResistance);
@@ -1594,7 +1608,7 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas
// Spells with melee and magic school mask, decide whether resistance or armor absorb is higher
if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
{
- uint32 damageAfterArmor = CalcArmorReducedDamage(victim, damage, spellInfo, BASE_ATTACK);
+ uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, BASE_ATTACK);
float armorReduction = damage - damageAfterArmor;
// pick the lower one, the weakest resistance counts
@@ -1606,20 +1620,22 @@ uint32 Unit::CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMas
return uint32(damageResisted);
}
-float Unit::CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo) const
+/*static*/ float Unit::CalculateAverageResistReduction(Unit const* attacker, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo)
{
float victimResistance = float(victim->GetResistance(schoolMask));
-
- // pets inherit 100% of masters penetration
- // excluding traps
- Player const* player = GetSpellModOwner();
- if (player && GetEntry() != WORLD_TRIGGER)
+ if (attacker)
{
- victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
- victimResistance -= float(player->GetSpellPenetrationItemMod());
+ // pets inherit 100% of masters penetration
+ // excluding traps
+ Player const* player = attacker->GetSpellModOwner();
+ if (player && attacker->GetEntry() != WORLD_TRIGGER)
+ {
+ victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
+ victimResistance -= float(player->GetSpellPenetrationItemMod());
+ }
+ else
+ victimResistance += float(attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
}
- else
- victimResistance += float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
// holy resistance exists in pve and comes from level difference, ignore template values
if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
@@ -1632,8 +1648,8 @@ float Unit::CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit con
victimResistance = std::max(victimResistance, 0.0f);
// level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
- if (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
- victimResistance += std::max((float(victim->getLevelForTarget(this)) - float(getLevelForTarget(victim))) * 5.0f, 0.0f);
+ if (attacker && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL)))
+ victimResistance += std::max((float(victim->getLevelForTarget(attacker)) - float(attacker->getLevelForTarget(victim))) * 5.0f, 0.0f);
static uint32 const BOSS_LEVEL = 83;
static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
@@ -1648,26 +1664,30 @@ float Unit::CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit con
return victimResistance / (victimResistance + resistanceConstant);
}
-void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
+/*static*/ void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
{
if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
return;
- uint32 resistedDamage = CalcSpellResistedDamage(damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
+ uint32 resistedDamage = Unit::CalcSpellResistedDamage(damageInfo.GetAttacker(), damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
damageInfo.ResistDamage(resistedDamage);
// Ignore Absorption Auras
- float auraAbsorbMod(GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask()));
- auraAbsorbMod = std::max(auraAbsorbMod, static_cast<float>(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL, [&damageInfo](AuraEffect const* aurEff) -> bool
+ float auraAbsorbMod = 0.f;
+ if (Unit* attacker = damageInfo.GetAttacker())
{
- if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
- return false;
+ auraAbsorbMod = attacker->GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask());
+ auraAbsorbMod = std::max(auraAbsorbMod, static_cast<float>(attacker->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL, [&damageInfo](AuraEffect const* aurEff) -> bool
+ {
+ if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
+ return false;
- if (!aurEff->IsAffectedOnSpell(damageInfo.GetSpellInfo()))
- return false;
+ if (!aurEff->IsAffectedOnSpell(damageInfo.GetSpellInfo()))
+ return false;
- return true;
- })));
+ return true;
+ })));
+ }
RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
@@ -1785,7 +1805,7 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
damageInfo.ModifyDamage(absorbIgnoringDamage);
// split damage auras - only when not damaging self
- if (damageInfo.GetVictim() != this)
+ if (damageInfo.GetVictim() != damageInfo.GetAttacker())
{
// 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
@@ -1820,12 +1840,13 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
uint32 splitted = splitDamage;
uint32 splitted_absorb = 0;
- DealDamageMods(caster, splitted, &splitted_absorb);
+ Unit::DealDamageMods(caster, splitted, &splitted_absorb);
- SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, damageInfo.GetSchoolMask(), splitted_absorb, 0, false, 0, false);
+ if (Unit* attacker = damageInfo.GetAttacker())
+ attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitted, damageInfo.GetSchoolMask(), splitted_absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
+ Unit::DealDamage(damageInfo.GetAttacker(), caster, splitted, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
}
// We're going to call functions which can modify content of the list during iteration over it's elements
@@ -1864,20 +1885,21 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo)
}
uint32 split_absorb = 0;
- DealDamageMods(caster, splitDamage, &split_absorb);
+ Unit::DealDamageMods(caster, splitDamage, &split_absorb);
- SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, false, 0, false);
+ if (Unit* attacker = damageInfo.GetAttacker())
+ attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo()->Id, splitDamage, damageInfo.GetSchoolMask(), split_absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
+ Unit::DealDamage(damageInfo.GetAttacker(), caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
// break 'Fear' and similar auras
- ProcSkillsAndAuras(caster, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, PROC_HIT_NONE, nullptr, &damageInfo, nullptr);
+ Unit::ProcSkillsAndAuras(damageInfo.GetAttacker(), caster, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, PROC_HIT_NONE, nullptr, &damageInfo, nullptr);
}
}
}
-void Unit::CalcHealAbsorb(HealInfo& healInfo) const
+/*static*/ void Unit::CalcHealAbsorb(HealInfo& healInfo)
{
if (!healInfo.GetHeal())
return;
@@ -1971,13 +1993,13 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
CalcDamageInfo damageInfo;
CalculateMeleeDamage(victim, 0, &damageInfo, attType);
// Send log damage message to client
- DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb);
+ Unit::DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
DealMeleeDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo);
- ProcSkillsAndAuras(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
+ Unit::ProcSkillsAndAuras(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
if (GetTypeId() == TYPEID_PLAYER)
TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
@@ -2055,7 +2077,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackTy
int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, attackerWeaponSkill - victimMaxSkillValueForLevel, 0) * 100.0f);
// Critical hit chance
- int32 crit_chance = int32(GetUnitCriticalChance(attType, victim) * 100.0f);
+ int32 crit_chance = int32(GetUnitCriticalChanceAgainst(attType, victim) * 100.0f);
int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
@@ -2534,7 +2556,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
// resistance chance for binary spells, equals to average damage reduction of non-binary spell
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL) && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_MAGIC))
- resist_chance += int32(CalculateAverageResistReduction(spellInfo->GetSchoolMask(), victim, spellInfo) * 10000.f); // 100 for spell calculations, and 100 for return value percentage
+ resist_chance += int32(Unit::CalculateAverageResistReduction(this, spellInfo->GetSchoolMask(), victim, spellInfo) * 10000.f); // 100 for spell calculations, and 100 for return value percentage
}
// Roll chance
@@ -2781,14 +2803,9 @@ float Unit::GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) con
return std::max(chance, 0.0f);
}
-float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const
+float Unit::GetUnitCriticalChanceDone(WeaponAttackType attackType) const
{
- int32 const attackerWeaponSkill = GetWeaponSkillValue(attackType, victim);
- int32 const victimDefenseSkill = victim->GetDefenseSkillValue(this);
- int32 const skillDiff = victimDefenseSkill - attackerWeaponSkill;
-
- float chance = 0.0f;
- float skillBonus = 0.0f;
+ float chance = 0.f;
if (GetTypeId() == TYPEID_PLAYER)
{
switch (attackType)
@@ -2818,29 +2835,40 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victi
}
}
+ return chance;
+}
+
+float Unit::GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const
+{
+ int32 const attackerWeaponSkill = attacker->GetWeaponSkillValue(attackType, this);
+ int32 const victimDefenseSkill = GetDefenseSkillValue(attacker);
+ int32 const skillDiff = victimDefenseSkill - attackerWeaponSkill;
+
+ float skillBonus = 0.0f;
+ float chance = critDone;
+
// flat aura mods
if (attackType == RANGED_ATTACK)
- chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE);
+ chance += GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE);
else
- chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
+ chance += GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
- chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [this](AuraEffect const* aurEff) -> bool
+ chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [attacker](AuraEffect const* aurEff) -> bool
{
- if (aurEff->GetCasterGUID() == GetGUID())
+ if (aurEff->GetCasterGUID() == attacker->GetGUID())
return true;
return false;
});
- chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
-
// reduce crit chance from Rating for players
- if (attackType != RANGED_ATTACK)
- ApplyResilience(victim, &chance, nullptr, false, CR_CRIT_TAKEN_MELEE);
- else
- ApplyResilience(victim, &chance, nullptr, false, CR_CRIT_TAKEN_RANGED);
+ if (attacker->CanApplyResilience())
+ Unit::ApplyResilience(this, &chance, nullptr, false, (attackType == RANGED_ATTACK ? CR_CRIT_TAKEN_RANGED : CR_CRIT_TAKEN_MELEE));
+
+ // applied after resilience
+ chance += GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
// Apply crit chance from defense skill
- if (victim->GetTypeId() == TYPEID_PLAYER)
+ if (GetTypeId() == TYPEID_PLAYER)
skillBonus = -skillDiff * 0.04f;
else
{
@@ -2850,7 +2878,13 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victi
}
chance += skillBonus;
- return std::max(chance, 0.0f);
+ return std::max(chance, 0.f);
+}
+
+float Unit::GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const
+{
+ float chance = GetUnitCriticalChanceDone(attackType);
+ return victim->GetUnitCriticalChanceTaken(this, attackType, chance);
}
uint32 Unit::GetWeaponSkillValue(WeaponAttackType attType, Unit const* target) const
@@ -3442,7 +3476,6 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask)
if (aurApp->GetRemoveMode())
return;
- aura->HandleAuraSpecificPeriodics(aurApp, caster);
aura->HandleAuraSpecificMods(aurApp, caster, true, false);
// apply effects of the aura
@@ -3953,7 +3986,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U
caster->GetSingleCastAuras().push_back(aura);
}
// FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
- newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, &damage[0]);
+ newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, aura->GetCritChance(), aura->CanApplyResilience(), &damage[0]);
newAura->ApplyForTargets();
}
}
@@ -5215,16 +5248,17 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damag
SendSpellNonMeleeDamageLog(&log);
}
-void Unit::ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
+/*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
{
WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
- if (typeMaskActor)
- ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
+ if (typeMaskActor && actor)
+ actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
if (typeMaskActionTarget && actionTarget)
- actionTarget->ProcSkillsAndReactives(true, this, typeMaskActionTarget, hitMask, attType);
+ actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
- TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
+ if (actor)
+ actor->TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
}
void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo)
@@ -6340,39 +6374,45 @@ void Unit::SetCharm(Unit* charm, bool apply)
UpdatePetCombatState();
}
-void Unit::DealHeal(HealInfo& healInfo)
+/*static*/ void Unit::DealHeal(HealInfo& healInfo)
{
int32 gain = 0;
+ Unit* healer = healInfo.GetHealer();
Unit* victim = healInfo.GetTarget();
uint32 addhealth = healInfo.GetHeal();
- if (victim->IsAIEnabled)
- victim->GetAI()->HealReceived(this, addhealth);
+ if (healer)
+ {
+ if (victim->IsAIEnabled)
+ victim->GetAI()->HealReceived(healer, addhealth);
- if (IsAIEnabled)
- GetAI()->HealDone(victim, addhealth);
+ if (healer->IsAIEnabled)
+ healer->GetAI()->HealDone(victim, addhealth);
+ }
if (addhealth)
gain = victim->ModifyHealth(int32(addhealth));
// Hook for OnHeal Event
- sScriptMgr->OnHeal(this, victim, (uint32&)gain);
+ sScriptMgr->OnHeal(healer, victim, (uint32&)gain);
- Unit* unit = this;
+ Unit* unit = healer;
+ if (healer && healer->GetTypeId() == TYPEID_UNIT && healer->IsTotem())
+ unit = healer->GetOwner();
- if (GetTypeId() == TYPEID_UNIT && IsTotem())
- unit = GetOwner();
-
- if (Player* player = unit->ToPlayer())
+ if (unit)
{
- if (Battleground* bg = player->GetBattleground())
- bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
+ if (Player* player = unit->ToPlayer())
+ {
+ if (Battleground* bg = player->GetBattleground())
+ bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
- // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
- if (gain)
- player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, victim);
+ // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
+ if (gain)
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, victim);
- player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth);
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth);
+ }
}
if (Player* player = victim->ToPlayer())
@@ -6615,9 +6655,8 @@ void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
{
// calculate heal absorb and reduce healing
- CalcHealAbsorb(healInfo);
-
- DealHeal(healInfo);
+ Unit::CalcHealAbsorb(healInfo);
+ Unit::DealHeal(healInfo);
SendHealSpellLog(healInfo, critical);
return healInfo.GetEffectiveHeal();
}
@@ -6647,7 +6686,7 @@ void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damag
victim->GetThreatManager().ForwardThreatForAssistingMe(this, float(damage)/2, spellInfo, true);
}
-uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) const
+uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, Optional<float> const& donePctTotal, uint32 stack /*= 1*/) const
{
if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
return pdamage;
@@ -6659,20 +6698,20 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
// For totems get damage bonus from owner
if (GetTypeId() == TYPEID_UNIT && IsTotem())
if (Unit* owner = GetOwner())
- return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype);
+ return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, donePctTotal, stack);
float ApCoeffMod = 1.0f;
int32 DoneTotal = 0;
+ float DoneTotalMod = donePctTotal ? *donePctTotal : SpellDamagePctDone(victim, spellProto, damagetype);
// done scripted mod (take it from owner)
Unit const* owner = GetOwner() ? GetOwner() : this;
- AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
+ DoneTotal += owner->GetTotalAuraModifier(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, [spellProto](AuraEffect const* aurEff) -> bool
{
- if (!(*i)->IsAffectedOnSpell(spellProto))
- continue;
+ if (!aurEff->IsAffectedOnSpell(spellProto))
+ return false;
- switch ((*i)->GetMiscValue())
+ switch (aurEff->GetMiscValue())
{
case 4418: // Increased Shock Damage
case 4554: // Increased Lightning Damage
@@ -6682,12 +6721,17 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
case 5148: // Idol of the Shooting Star
case 6008: // Increased Lightning Damage
case 8627: // Totem of Hex
- {
- DoneTotal += (*i)->GetAmount();
+ return true;
+ default:
break;
- }
}
- }
+
+ return false;
+ });
+
+ // Some spells don't benefit from pct done mods
+ if (!spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS))
+ DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, victim->GetCreatureTypeMask());
// Custom scripted damage
switch (spellProto->SpellFamilyName)
@@ -6711,7 +6755,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
case 49638:
if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first))
AddPct(ApCoeffMod, proto->Effects[EFFECT_0].CalcValue());
- break;
+ break;
}
}
}
@@ -6765,18 +6809,11 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
}
- float tmpDamage = (int32(pdamage) + DoneTotal);
+ float tmpDamage = float(int32(pdamage) + DoneTotal) * DoneTotalMod;
- // DOTs calculated in AuraEffect::PeriodicDamageAurasTick
- // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods.
- if (damagetype != DOT)
- {
- tmpDamage *= SpellDamagePctDone(victim, spellProto, damagetype);
-
- // apply spellmod to Done damage (flat and pct)
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
- }
+ // apply spellmod to Done damage (flat and pct)
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
return uint32(std::max(tmpDamage, 0.0f));
}
@@ -6786,13 +6823,18 @@ float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, Damage
if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
return 1.0f;
+ // Some spells don't benefit from done mods
+ if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
+ return 1.0f;
+
// Some spells don't benefit from pct done mods
if (spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS))
return 1.0f;
- // For totems pct done mods are calculated when its calculation is run on the player in SpellDamageBonusDone.
+ // For totems get damage bonus from owner
if (GetTypeId() == TYPEID_UNIT && IsTotem())
- return 1.0f;
+ if (Unit* owner = GetOwner())
+ return owner->SpellDamagePctDone(victim, spellProto, damagetype);
// Done total percent damage auras
float DoneTotalMod = 1.0f;
@@ -7221,94 +7263,84 @@ int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const
return GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, schoolMask);
}
-bool Unit::IsSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const
+float Unit::SpellCritChanceDone(SpellInfo const* spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const
{
- return roll_chance_f(GetUnitSpellCriticalChance(victim, spellProto, schoolMask, attackType));
-}
-
-float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const
-{
- //! Mobs can't crit with spells. Player Totems can
- //! Fire Elemental (from totem) can too - but this part is a hack and needs more research
- if (GetGUID().IsCreatureOrVehicle() && !(IsTotem() && GetOwnerGUID().IsPlayer()) && GetEntry() != 15438)
+ //! Mobs can't crit with spells. (Except player controlled)
+ if (GetTypeId() == TYPEID_UNIT && !GetSpellModOwner())
return 0.0f;
// not critting spell
- if (spellProto->HasAttribute(SPELL_ATTR2_CANT_CRIT))
+ if (spellInfo->HasAttribute(SPELL_ATTR2_CANT_CRIT))
return 0.0f;
float crit_chance = 0.0f;
- switch (spellProto->DmgClass)
+ switch (spellInfo->DmgClass)
{
- case SPELL_DAMAGE_CLASS_NONE:
- // We need more spells to find a general way (if there is any)
- switch (spellProto->Id)
- {
- case 379: // Earth Shield
- case 33778: // Lifebloom Final Bloom
- case 64844: // Divine Hymn
- case 71607: // Item - Bauble of True Blood 10m
- case 71646: // Item - Bauble of True Blood 25m
- break;
- default:
- return 0.0f;
- }
- // Do not add a break here, case fallthrough is intentional! Adding a break will make above spells unable to crit.
case SPELL_DAMAGE_CLASS_MAGIC:
{
if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
crit_chance = 0.0f;
// For other schools
else if (GetTypeId() == TYPEID_PLAYER)
- {
crit_chance = GetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask));
-
- // register aura mod, this is needed for Arcane Potency
- if (Spell* spell = ToPlayer()->m_spellModTakingSpell)
- {
- std::vector<Aura*> affectingAuras;
- (void)GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE, [&affectingAuras](AuraEffect const* aurEff) -> bool
- {
- affectingAuras.push_back(aurEff->GetBase());
- return true;
- });
-
- (void)GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, [&affectingAuras, schoolMask](AuraEffect const* aurEff) -> bool
- {
- if ((aurEff->GetMiscValue() & schoolMask) != 0)
- {
- affectingAuras.push_back(aurEff->GetBase());
- return true;
- }
-
- return false;
- });
-
- for (Aura* aura : affectingAuras)
- spell->m_appliedMods.insert(aura);
- }
- }
else
{
crit_chance = (float)m_baseSpellCritChance;
crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
}
+ break;
+ }
+ case SPELL_DAMAGE_CLASS_MELEE:
+ case SPELL_DAMAGE_CLASS_RANGED:
+ {
+ crit_chance += GetUnitCriticalChanceDone(attackType);
+ crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
+ break;
+ }
+ case SPELL_DAMAGE_CLASS_NONE:
+ default:
+ return 0.0f;
+ }
+ // percent done
+ // only players use intelligence for critical chance computations
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
+
+ return std::max(crit_chance, 0.0f);
+}
+
+float Unit::SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType /*= BASE_ATTACK*/) const
+{
+ // not critting spell
+ if (spellInfo->HasAttribute(SPELL_ATTR2_CANT_CRIT))
+ return 0.0f;
+
+ float crit_chance = doneChance;
+ switch (spellInfo->DmgClass)
+ {
+ case SPELL_DAMAGE_CLASS_MAGIC:
+ {
// taken
- if (victim)
+ if (!spellInfo->IsPositive())
{
- if (!spellProto->IsPositive())
- {
- // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
- crit_chance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
- // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
- crit_chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
- ApplyResilience(victim, &crit_chance, nullptr, false, CR_CRIT_TAKEN_SPELL);
- }
- // scripted (increase crit chance ... against ... target by x%
- AuraEffectList const& mOverrideClassScript = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
+ crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
+
+ if (caster && caster->CanApplyResilience())
+ Unit::ApplyResilience(this, &crit_chance, nullptr, false, CR_CRIT_TAKEN_SPELL);
+
+ // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
+ // applied after resilience
+ crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
+ }
+
+ // scripted (increase crit chance ... against ... target by x%
+ if (caster)
+ {
+ AuraEffectList const& mOverrideClassScript = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
for (AuraEffect const* aurEff : mOverrideClassScript)
{
- if (!aurEff->IsAffectedOnSpell(spellProto))
+ if (!aurEff->IsAffectedOnSpell(spellInfo))
continue;
float modChance = 0.f;
@@ -7320,18 +7352,18 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
modChance += 17.f;
case 849: // Shatter (Rank 1)
modChance += 17.f;
- if (!victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
+ if (!HasAuraState(AURA_STATE_FROZEN, spellInfo, caster))
break;
crit_chance += modChance;
break;
case 7917: // Glyph of Shadowburn
- if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
+ if (HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellInfo, caster))
crit_chance += aurEff->GetAmount();
break;
case 7997: // Renewed Hope
case 7998:
- if (victim->HasAura(6788))
+ if (HasAura(6788))
crit_chance += aurEff->GetAmount();
break;
default:
@@ -7339,61 +7371,61 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
}
}
// Custom crit by class
- switch (spellProto->SpellFamilyName)
+ switch (spellInfo->SpellFamilyName)
{
case SPELLFAMILY_MAGE:
// Glyph of Fire Blast
- if (spellProto->SpellFamilyFlags[0] == 0x2 && spellProto->SpellIconID == 12)
- if (victim->HasAuraWithMechanic((1 << MECHANIC_STUN) | (1 << MECHANIC_KNOCKOUT)))
- if (AuraEffect const* aurEff = GetAuraEffect(56369, EFFECT_0))
+ if (spellInfo->SpellFamilyFlags[0] == 0x2 && spellInfo->SpellIconID == 12)
+ if (HasAuraWithMechanic((1 << MECHANIC_STUN) | (1 << MECHANIC_KNOCKOUT)))
+ if (AuraEffect const* aurEff = caster->GetAuraEffect(56369, EFFECT_0))
crit_chance += aurEff->GetAmount();
break;
case SPELLFAMILY_DRUID:
// Improved Faerie Fire
- if (victim->HasAuraState(AURA_STATE_FAERIE_FIRE))
- if (AuraEffect const* aurEff = GetDummyAuraEffect(SPELLFAMILY_DRUID, 109, 0))
+ if (HasAuraState(AURA_STATE_FAERIE_FIRE))
+ if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 109, 0))
crit_chance += aurEff->GetAmount();
// cumulative effect - don't break
// Starfire
- if (spellProto->SpellFamilyFlags[0] & 0x4 && spellProto->SpellIconID == 1485)
+ if (spellInfo->SpellFamilyFlags[0] & 0x4 && spellInfo->SpellIconID == 1485)
{
// Improved Insect Swarm
- if (AuraEffect const* aurEff = GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0))
- if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00000002, 0, 0))
+ if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0))
+ if (GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00000002, 0, 0))
crit_chance += aurEff->GetAmount();
- break;
+ break;
}
break;
case SPELLFAMILY_ROGUE:
// Shiv-applied poisons can't crit
- if (FindCurrentSpellBySpellId(5938))
+ if (caster->FindCurrentSpellBySpellId(5938))
crit_chance = 0.0f;
break;
case SPELLFAMILY_PALADIN:
// Flash of light
- if (spellProto->SpellFamilyFlags[0] & 0x40000000)
+ if (spellInfo->SpellFamilyFlags[0] & 0x40000000)
{
// Sacred Shield
- if (AuraEffect const* aura = victim->GetAuraEffect(58597, 1, GetGUID()))
+ if (AuraEffect const* aura = GetAuraEffect(58597, 1, GetGUID()))
crit_chance += aura->GetAmount();
break;
}
// Exorcism
- else if (spellProto->GetCategory() == 19)
+ else if (spellInfo->GetCategory() == 19)
{
- if (victim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD)
+ if (GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD)
return 100.0f;
break;
}
break;
case SPELLFAMILY_SHAMAN:
// Lava Burst
- if (spellProto->SpellFamilyFlags[1] & 0x00001000)
+ if (spellInfo->SpellFamilyFlags[1] & 0x00001000)
{
- if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, GetGUID()))
- if (victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE) > -100)
+ if (GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, GetGUID()))
+ if (GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE) > -100)
return 100.0f;
break;
}
@@ -7401,67 +7433,61 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
}
// Spell crit suppression
- if (victim->GetTypeId() == TYPEID_UNIT)
+ if (GetTypeId() == TYPEID_UNIT)
{
- int32 const levelDiff = static_cast<int32>(victim->getLevelForTarget(this)) - getLevel();
+ int32 const levelDiff = static_cast<int32>(getLevelForTarget(caster)) - caster->getLevel();
crit_chance -= levelDiff * 0.7f;
}
}
break;
}
case SPELL_DAMAGE_CLASS_MELEE:
- if (victim)
+ {
+ // Custom crit by class
+ if (caster)
{
- // Custom crit by class
- switch (spellProto->SpellFamilyName)
+ switch (spellInfo->SpellFamilyName)
{
case SPELLFAMILY_DRUID:
// Rend and Tear - bonus crit chance for Ferocious Bite on bleeding targets
- if (spellProto->SpellFamilyFlags[0] & 0x00800000
- && spellProto->SpellIconID == 1680
- && victim->HasAuraState(AURA_STATE_BLEEDING))
+ if (spellInfo->SpellFamilyFlags[0] & 0x00800000
+ && spellInfo->SpellIconID == 1680
+ && HasAuraState(AURA_STATE_BLEEDING))
{
- if (AuraEffect const* rendAndTear = GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 1))
+ if (AuraEffect const* rendAndTear = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 1))
crit_chance += rendAndTear->GetAmount();
break;
}
break;
case SPELLFAMILY_WARRIOR:
// Victory Rush
- if (spellProto->SpellFamilyFlags[1] & 0x100)
+ if (spellInfo->SpellFamilyFlags[1] & 0x100)
{
// Glyph of Victory Rush
- if (AuraEffect const* aurEff = GetAuraEffect(58382, 0))
+ if (AuraEffect const* aurEff = caster->GetAuraEffect(58382, 0))
crit_chance += aurEff->GetAmount();
break;
}
break;
}
}
+ }
/// Intentional fallback. Calculate critical strike chance for both Ranged and Melee spells
case SPELL_DAMAGE_CLASS_RANGED:
- {
- if (victim)
- {
- crit_chance += GetUnitCriticalChance(attackType, victim);
- crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
- }
+ if (caster)
+ crit_chance = GetUnitCriticalChanceTaken(caster, attackType, crit_chance);
break;
- }
+ case SPELL_DAMAGE_CLASS_NONE:
default:
- return 0.0f;
+ return 0.f;
}
- // percent done
- // only players use intelligence for critical chance computations
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
// for this types the bonus was already added in GetUnitCriticalChance, do not add twice
- if (spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellProto->DmgClass != SPELL_DAMAGE_CLASS_RANGED)
+ if (caster && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED)
{
- crit_chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [this, spellProto](AuraEffect const* aurEff) -> bool
+ crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster, spellInfo](AuraEffect const* aurEff) -> bool
{
- if (aurEff->GetCasterGUID() == GetGUID() && aurEff->IsAffectedOnSpell(spellProto))
+ if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectedOnSpell(spellInfo))
return true;
return false;
});
@@ -7470,7 +7496,7 @@ float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto
return std::max(crit_chance, 0.0f);
}
-uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim)
+/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
{
// Calculate critical bonus
int32 crit_bonus = damage;
@@ -7488,29 +7514,32 @@ uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage
break;
}
- crit_mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100;
+ if (caster)
+ {
+ crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100;
- if (victim)
- crit_mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, victim->GetCreatureTypeMask());
+ if (victim)
+ crit_mod += caster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, victim->GetCreatureTypeMask());
- if (crit_bonus != 0)
- AddPct(crit_bonus, crit_mod);
+ if (crit_bonus != 0)
+ AddPct(crit_bonus, crit_mod);
- crit_bonus -= damage;
+ crit_bonus -= damage;
- if (damage > uint32(crit_bonus))
- {
- // adds additional damage to critBonus (from talents)
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
- }
+ if (damage > uint32(crit_bonus))
+ {
+ // adds additional damage to critBonus (from talents)
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
+ }
- crit_bonus += damage;
+ crit_bonus += damage;
+ }
return crit_bonus;
}
-uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim)
+/*static*/ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
{
// Calculate critical bonus
int32 crit_bonus;
@@ -7526,26 +7555,30 @@ uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damag
break;
}
- if (victim)
+ if (caster)
{
- uint32 creatureTypeMask = victim->GetCreatureTypeMask();
- crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
+ if (victim)
+ {
+ uint32 creatureTypeMask = victim->GetCreatureTypeMask();
+ crit_bonus = int32(crit_bonus * caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
+ }
}
if (crit_bonus > 0)
damage += crit_bonus;
- damage = int32(float(damage) * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
+ if (caster)
+ damage = int32(float(damage) * caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
return damage;
}
-uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) const
+uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, Optional<float> const& donePctTotal, uint32 stack /*= 1*/) const
{
// For totems get healing bonus from owner (statue isn't totem in fact)
if (GetTypeId() == TYPEID_UNIT && IsTotem())
if (Unit* owner = GetOwner())
- return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, stack);
+ return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, donePctTotal, stack);
// No bonus healing for potion spells
if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
@@ -7553,20 +7586,22 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
float ApCoeffMod = 1.0f;
int32 DoneTotal = 0;
+ float DoneTotalMod = donePctTotal ? *donePctTotal : SpellHealingPctDone(victim, spellProto);
// done scripted mod (take it from owner)
Unit const* owner = GetOwner() ? GetOwner() : this;
AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
+ for (AuraEffect const* aurEff : mOverrideClassScript)
{
- if (!(*i)->IsAffectedOnSpell(spellProto))
+ if (!aurEff->IsAffectedOnSpell(spellProto))
continue;
- switch ((*i)->GetMiscValue())
+
+ switch (aurEff->GetMiscValue())
{
case 4415: // Increased Rejuvenation Healing
case 4953:
case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
- DoneTotal += (*i)->GetAmount();
+ DoneTotal += aurEff->GetAmount();
break;
default:
break;
@@ -7669,26 +7704,28 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
DoneTotal = 0;
}
- float heal = float(int32(healamount) + DoneTotal);
+ float heal = float(int32(healamount) + DoneTotal) * DoneTotalMod;
- // DOTs calculated in AuraEffect::HandlePeriodicHealAurasTick
- // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods.
- if (damagetype != DOT)
- {
- heal *= SpellHealingPctDone(victim, spellProto);
-
- // apply spellmod to Done amount
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, heal);
- }
+ // apply spellmod to Done amount
+ if (Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
return uint32(std::max(heal, 0.0f));
}
float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
{
- // For totems pct done mods are calculated when its calculation is run on the player in SpellHealingBonusDone.
+ // For totems get healing bonus from owner
if (GetTypeId() == TYPEID_UNIT && IsTotem())
+ if (Unit* owner = GetOwner())
+ return owner->SpellHealingPctDone(victim, spellProto);
+
+ // Some spells don't benefit from done mods
+ if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
+ return 1.0f;
+
+ // Some spells don't benefit from done mods
+ if (spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_HEALING_MODS))
return 1.0f;
// No bonus healing for potion spells
@@ -7703,27 +7740,28 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
// done scripted mod (take it from owner)
Unit const* owner = GetOwner() ? GetOwner() : this;
AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
+ for (AuraEffect const* aurEff : mOverrideClassScript)
{
- if (!(*i)->IsAffectedOnSpell(spellProto))
+ if (!aurEff->IsAffectedOnSpell(spellProto))
continue;
- switch ((*i)->GetMiscValue())
+
+ switch (aurEff->GetMiscValue())
{
case 21: // Test of Faith
case 6935:
case 6918:
if (victim->HealthBelowPct(50))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ AddPct(DoneTotalMod, aurEff->GetAmount());
break;
case 7798: // Glyph of Regrowth
{
if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x40, 0, 0))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ AddPct(DoneTotalMod, aurEff->GetAmount());
break;
}
case 8477: // Nourish Heal Boost
{
- int32 stepPercent = (*i)->GetAmount();
+ int32 stepPercent = aurEff->GetAmount();
int32 modPercent = 0;
AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
@@ -7731,6 +7769,7 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
Aura const* aura = itr->second->GetBase();
if (aura->GetCasterGUID() != GetGUID())
continue;
+
SpellInfo const* m_spell = aura->GetSpellInfo();
if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID ||
!(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50))
@@ -7742,8 +7781,8 @@ float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
}
case 7871: // Glyph of Lesser Healing Wave
{
- if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0, GetGUID()))
- AddPct(DoneTotalMod, (*i)->GetAmount());
+ if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0))
+ AddPct(DoneTotalMod, aurEff->GetAmount());
break;
}
default:
@@ -11591,14 +11630,20 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
return true;
}
-void Unit::Kill(Unit* victim, bool durabilityLoss)
+/*static*/ void Unit::Kill(Unit* attacker, Unit* victim, bool durabilityLoss /*= true*/)
{
// Prevent killing unit twice (and giving reward from kill twice)
if (!victim->GetHealth())
return;
+ if (attacker && !attacker->IsInMap(victim))
+ attacker = nullptr;
+
// find player: owner of controlled `this` or `this` itself maybe
- Player* player = GetCharmerOrOwnerPlayerOrPlayerItself();
+ Player* player = nullptr;
+ if (attacker)
+ player = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
+
Creature* creature = victim->ToCreature();
bool isRewardAllowed = true;
@@ -11689,48 +11734,44 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
}
// Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim
- if (IsPet() || IsTotem())
+ if (attacker && (attacker->IsPet() || attacker->IsTotem()))
{
// proc only once for victim
- if (Unit* owner = GetOwner())
- owner->ProcSkillsAndAuras(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
+ if (Unit* owner = attacker->GetOwner())
+ Unit::ProcSkillsAndAuras(owner, victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
}
if (!victim->IsCritter())
- ProcSkillsAndAuras(victim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
+ Unit::ProcSkillsAndAuras(attacker, victim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
// Proc auras on death - must be before aura/combat remove
- victim->ProcSkillsAndAuras(victim, PROC_FLAG_NONE, PROC_FLAG_DEATH, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
+ Unit::ProcSkillsAndAuras(victim, victim, PROC_FLAG_NONE, PROC_FLAG_DEATH, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
// update get killing blow achievements, must be done before setDeathState to be able to require auras on target
// and before Spirit of Redemption as it also removes auras
- if (Player* killerPlayer = GetCharmerOrOwnerPlayerOrPlayerItself())
- killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, victim);
+ if (attacker)
+ if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
+ killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, victim);
+ // Spirit of Redemption
// if talent known but not triggered (check priest class for speedup check)
bool spiritOfRedemption = false;
if (victim->GetTypeId() == TYPEID_PLAYER && victim->getClass() == CLASS_PRIEST)
{
- AuraEffectList const& dummyAuras = victim->GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for (AuraEffectList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
+ if (AuraEffect const* aurEff = victim->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 1654, EFFECT_0))
{
- if ((*itr)->GetSpellInfo()->SpellIconID == 1654)
- {
- AuraEffect const* aurEff = *itr;
- // save value before aura remove
- uint32 ressSpellId = victim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
- if (!ressSpellId)
- ressSpellId = victim->ToPlayer()->GetResurrectionSpellId();
- // Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
- victim->RemoveAllAurasOnDeath();
- // restore for use at real death
- victim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
+ // save value before aura remove
+ uint32 ressSpellId = victim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
+ if (!ressSpellId)
+ ressSpellId = victim->ToPlayer()->GetResurrectionSpellId();
+ // Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
+ victim->RemoveAllAurasOnDeath();
+ // restore for use at real death
+ victim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
- // FORM_SPIRITOFREDEMPTION and related auras
- victim->CastSpell(victim, 27827, aurEff);
- spiritOfRedemption = true;
- break;
- }
+ // FORM_SPIRITOFREDEMPTION and related auras
+ victim->CastSpell(victim, 27827, aurEff);
+ spiritOfRedemption = true;
}
}
@@ -11767,8 +11808,8 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
plrVictim->SendDirectMessage(&data);
}
// Call KilledUnit for creatures
- if (GetTypeId() == TYPEID_UNIT && IsAIEnabled)
- ToCreature()->AI()->KilledUnit(victim);
+ if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled)
+ attacker->ToCreature()->AI()->KilledUnit(victim);
// last damage from non duel opponent or opponent controlled creature
if (plrVictim->duel)
@@ -11794,31 +11835,30 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
}
// Call KilledUnit for creatures, this needs to be called after the lootable flag is set
- if (GetTypeId() == TYPEID_UNIT && IsAIEnabled)
- ToCreature()->AI()->KilledUnit(victim);
+ if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled)
+ attacker->ToCreature()->AI()->KilledUnit(victim);
// Call creature just died function
if (creature->IsAIEnabled)
- creature->AI()->JustDied(this);
+ creature->AI()->JustDied(attacker);
if (TempSummon* summon = creature->ToTempSummon())
if (Unit* summoner = summon->GetSummoner())
if (summoner->ToCreature() && summoner->IsAIEnabled)
- summoner->ToCreature()->AI()->SummonedCreatureDies(creature, this);
+ summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker);
// Dungeon specific stuff, only applies to players killing creatures
if (creature->GetInstanceId())
{
Map* instanceMap = creature->GetMap();
- Player* creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself();
- /// @todo do instance binding anyway if the charmer/owner is offline
- if (instanceMap->IsDungeon() && (creditedPlayer || this == victim))
+ /// @todo do instance binding anyway if the charmer/owner is offline
+ if (instanceMap->IsDungeon() && ((attacker && attacker->GetCharmerOrOwnerPlayerOrPlayerItself()) || attacker == victim))
{
if (instanceMap->IsRaidOrHeroicDungeon())
{
if (creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
- ((InstanceMap*)instanceMap)->PermBindAllPlayers();
+ instanceMap->ToInstanceMap()->PermBindAllPlayers();
}
else
{
@@ -11835,7 +11875,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
// outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
// handle player kill only if not suicide (spirit of redemption for example)
- if (player && this != victim)
+ if (player && attacker != victim)
{
if (OutdoorPvP* pvp = player->GetOutdoorPvP())
pvp->HandleKill(player, victim);
@@ -11861,26 +11901,29 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
}
// achievement stuff
- if (victim->GetTypeId() == TYPEID_PLAYER)
+ if (attacker && victim->GetTypeId() == TYPEID_PLAYER)
{
- if (GetTypeId() == TYPEID_UNIT)
- victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
- else if (GetTypeId() == TYPEID_PLAYER && victim != this)
- victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ToPlayer()->GetTeam());
+ if (attacker->GetTypeId() == TYPEID_UNIT)
+ victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, attacker->GetEntry());
+ else if (attacker->GetTypeId() == TYPEID_PLAYER && victim != attacker)
+ victim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, attacker->ToPlayer()->GetTeam());
}
// Hook for OnPVPKill Event
- if (Player* killerPlr = ToPlayer())
- {
- if (Player* killedPlr = victim->ToPlayer())
- sScriptMgr->OnPVPKill(killerPlr, killedPlr);
- else if (Creature* killedCre = victim->ToCreature())
- sScriptMgr->OnCreatureKill(killerPlr, killedCre);
- }
- else if (Creature* killerCre = ToCreature())
+ if (attacker)
{
- if (Player* killed = victim->ToPlayer())
- sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
+ if (Player* killerPlr = attacker->ToPlayer())
+ {
+ if (Player* killedPlr = victim->ToPlayer())
+ sScriptMgr->OnPVPKill(killerPlr, killedPlr);
+ else if (Creature* killedCre = victim->ToCreature())
+ sScriptMgr->OnCreatureKill(killerPlr, killedCre);
+ }
+ else if (Creature* killerCre = attacker->ToCreature())
+ {
+ if (Player* killed = victim->ToPlayer())
+ sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
+ }
}
}
@@ -12649,23 +12692,26 @@ void Unit::SendPlaySpellImpact(ObjectGuid guid, uint32 id)
SendMessageToSet(&data, false);
}
-void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type) const
+bool Unit::CanApplyResilience() const
+{
+ return !IsVehicle() && GetOwnerGUID().IsPlayer();
+}
+
+/*static*/ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type)
{
// player mounted on multi-passenger mount is also classified as vehicle
- if (IsVehicle() || (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER))
+ if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)
return;
- Unit const* source = nullptr;
- if (GetTypeId() == TYPEID_PLAYER)
- source = this;
- else if (GetTypeId() == TYPEID_UNIT && GetOwner() && GetOwner()->GetTypeId() == TYPEID_PLAYER)
- source = GetOwner();
-
Unit const* target = nullptr;
if (victim->GetTypeId() == TYPEID_PLAYER)
target = victim;
- else if (victim->GetTypeId() == TYPEID_UNIT && victim->GetOwner() && victim->GetOwner()->GetTypeId() == TYPEID_PLAYER)
- target = victim->GetOwner();
+ else // victim->GetTypeId() == TYPEID_UNIT
+ {
+ if (Unit* owner = victim->GetOwner())
+ if (owner->GetTypeId() == TYPEID_PLAYER)
+ target = owner;
+ }
if (!target)
return;
@@ -12676,7 +12722,7 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool
// Crit chance reduction works against nonpets
if (crit)
*crit -= target->GetMeleeCritChanceReduction();
- if (source && damage)
+ if (damage)
{
if (isCrit)
*damage -= target->GetMeleeCritDamageReduction(*damage);
@@ -12687,7 +12733,7 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool
// Crit chance reduction works against nonpets
if (crit)
*crit -= target->GetRangedCritChanceReduction();
- if (source && damage)
+ if (damage)
{
if (isCrit)
*damage -= target->GetRangedCritDamageReduction(*damage);
@@ -12698,7 +12744,7 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool
// Crit chance reduction works against nonpets
if (crit)
*crit -= target->GetSpellCritChanceReduction();
- if (source && damage)
+ if (damage)
{
if (isCrit)
*damage -= target->GetSpellCritDamageReduction(*damage);
@@ -12710,6 +12756,15 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool
}
}
+int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, Unit* caster) const
+{
+ damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask));
+ if (caster->GetTypeId() == TYPEID_UNIT)
+ damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, schoolMask));
+
+ return damage;
+}
+
// Melee based spells can be miss, parry or dodge on this step
// Crit or block - determined on damage calculation phase! (and can be both in some time)
float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 6adf01b367c..407168b4dab 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -846,7 +846,7 @@ class TC_GAME_API Unit : public WorldObject
uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(UNIT_FIELD_RESISTANCES+school); }
uint32 GetResistance(SpellSchoolMask mask) const;
void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(UNIT_FIELD_RESISTANCES+school, val); }
- float CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr) const;
+ static float CalculateAverageResistReduction(Unit const* attacker, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo = nullptr);
uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); }
uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); }
@@ -921,13 +921,13 @@ class TC_GAME_API Unit : public WorldObject
void Dismount();
uint32 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
- void DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) const;
- uint32 DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true);
- void Kill(Unit* victim, bool durabilityLoss = true);
- void KillSelf(bool durabilityLoss = true) { Kill(this, durabilityLoss); }
- void DealHeal(HealInfo& healInfo);
+ static void DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb);
+ static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true);
+ static void Kill(Unit* attacker, Unit* victim, bool durabilityLoss = true);
+ void KillSelf(bool durabilityLoss = true) { Unit::Kill(this, this, durabilityLoss); }
+ static void DealHeal(HealInfo& healInfo);
- void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
+ static void ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell,
DamageInfo* damageInfo, HealInfo* healInfo);
@@ -964,7 +964,10 @@ class TC_GAME_API Unit : public WorldObject
uint32 GetRangedDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_RANGED, 2.0f, 100.0f, damage); }
uint32 GetSpellDamageReduction(uint32 damage) const { return GetCombatRatingDamageReduction(CR_CRIT_TAKEN_SPELL, 2.0f, 100.0f, damage); }
- void ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type) const;
+ virtual bool CanApplyResilience() const;
+ static void ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type);
+
+ int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, Unit* caster) const;
float MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
SpellMissInfo MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo) const;
@@ -975,7 +978,9 @@ class TC_GAME_API Unit : public WorldObject
float GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const;
float GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) const;
float GetUnitMissChance(WeaponAttackType attType) const;
- float GetUnitCriticalChance(WeaponAttackType attackType, Unit const* victim) const;
+ float GetUnitCriticalChanceDone(WeaponAttackType attackType) const;
+ float GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const;
+ float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const;
int32 GetMechanicResistChance(SpellInfo const* spellInfo) const;
bool CanUseAttackType(uint8 attacktype) const;
@@ -1500,12 +1505,12 @@ class TC_GAME_API Unit : public WorldObject
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const;
int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const;
- uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const;
+ uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, Optional<float> const& donePctTotal, uint32 stack = 1) const;
float SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const;
uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const;
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const;
int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const;
- uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const;
+ uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, Optional<float> const& donePctTotal, uint32 stack = 1) const;
float SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const;
uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const;
@@ -1514,10 +1519,10 @@ class TC_GAME_API Unit : public WorldObject
bool isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType = BASE_ATTACK);
bool isBlockCritical();
- bool IsSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const;
- float GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const;
- uint32 SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim);
- uint32 SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim);
+ float SpellCritChanceDone(SpellInfo const* spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const;
+ float SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType = BASE_ATTACK) const;
+ static uint32 SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim);
+ static uint32 SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim);
void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; }
bool IsUnderLastManaUseEffect() const;
@@ -1538,10 +1543,10 @@ class TC_GAME_API Unit : public WorldObject
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const; // redefined in Creature
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = nullptr, int8 effIndex = -1);
- uint32 CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK) const;
- uint32 CalcSpellResistedDamage(Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const;
- void CalcAbsorbResist(DamageInfo& damageInfo);
- void CalcHealAbsorb(HealInfo& healInfo) const;
+ static uint32 CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, uint8 attackerLevel = 0, WeaponAttackType attackType = MAX_ATTACK);
+ static uint32 CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo);
+ static void CalcAbsorbResist(DamageInfo& damageInfo);
+ static void CalcHealAbsorb(HealInfo& healInfo);
void UpdateSpeed(UnitMoveType mtype);
float GetSpeed(UnitMoveType mtype) const;
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 58266fc3559..f093b2cc508 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -381,13 +381,12 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster):
m_base(base), m_spellInfo(base->GetSpellInfo()),
m_baseAmount(baseAmount ? *baseAmount : m_spellInfo->Effects[effIndex].BasePoints),
-m_bonusAmount(0), m_critChance(0.0f), m_donePct(1.0f),
-m_spellmod(nullptr), _periodicTimer(0), _amplitude(0), _ticksDone(0), m_effIndex(effIndex),
+_amount(), m_spellmod(nullptr), _periodicTimer(0), _amplitude(0), _ticksDone(0), m_effIndex(effIndex),
m_canBeRecalculated(true), m_isPeriodic(false)
{
CalculatePeriodic(caster, true, false);
- m_amount = CalculateAmount(caster);
+ _amount = CalculateAmount(caster);
CalculateSpellMod();
}
@@ -493,6 +492,24 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
break;
}
+ if (caster)
+ {
+ switch (GetAuraType())
+ {
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_PERIODIC_LEECH:
+ if (GetBase()->GetType() == UNIT_AURA_TYPE)
+ amount = caster->SpellDamageBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, DOT, GetBase()->GetDonePct());
+ break;
+ case SPELL_AURA_PERIODIC_HEAL:
+ if (GetBase()->GetType() == UNIT_AURA_TYPE)
+ amount = caster->SpellHealingBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, DOT, GetBase()->GetDonePct());
+ break;
+ default:
+ break;
+ }
+ }
+
GetBase()->CallScriptEffectCalcAmountHandlers(this, amount, m_canBeRecalculated);
amount *= GetBase()->GetStackAmount();
return amount;
@@ -643,7 +660,7 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
if (handleMask & AURA_EFFECT_HANDLE_CHANGE_AMOUNT)
{
if (!mark)
- m_amount = newAmount;
+ _amount = newAmount;
else
SetAmount(newAmount);
CalculateSpellMod();
@@ -799,17 +816,9 @@ void AuraEffect::Update(uint32 diff, Unit* caster)
}
}
-bool AuraEffect::CanPeriodicTickCrit(Unit const* caster) const
+float AuraEffect::GetCritChanceFor(Unit const* caster, Unit const* target) const
{
- ASSERT(caster);
- if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, m_spellInfo))
- return true;
-
- // Rupture - since 3.3.3 can crit
- if (m_spellInfo->SpellIconID == 500 && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE)
- return true;
-
- return false;
+ return target->SpellCritChanceTaken(caster, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), GetBase()->GetCritChance(), GetSpellInfo()->GetAttackType());
}
bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const
@@ -2942,7 +2951,7 @@ void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 m
// so this break such spells or most of them.
// Current formula about m_amount: effect base points + dieside - 1
// TO DO: Reasearch more about 0/0 and fix it.
- caster->_EnterVehicle(target->GetVehicleKit(), m_amount - 1, aurApp);
+ caster->_EnterVehicle(target->GetVehicleKit(), GetAmount() - 1, aurApp);
}
else
{
@@ -2951,7 +2960,7 @@ void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 m
if (GetId() == 53111) // Devour Humanoid
{
- target->Kill(caster);
+ Unit::Kill(target, caster);
if (caster->GetTypeId() == TYPEID_UNIT)
caster->ToCreature()->DespawnOrUnsummon();
}
@@ -3381,7 +3390,7 @@ void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode,
if (GetMiscValue() == i || GetMiscValue() == -1)
{
if (apply)
- target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount));
+ target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(GetAmount()));
else
{
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff) -> bool
@@ -3930,7 +3939,7 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply);
}
- target->ApplyCastTimePercentMod(float(m_amount), apply);
+ target->ApplyCastTimePercentMod(float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(GetAmount()), apply);
@@ -4708,7 +4717,7 @@ void AuraEffect::HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mod
//Adding items
uint32 noSpaceForCount = 0;
- uint32 count = m_amount;
+ uint32 count = GetAmount();
ItemPosCountVec dest;
InventoryResult msg = plCaster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, GetSpellInfo()->Effects[m_effIndex].ItemType, count, &noSpaceForCount);
@@ -4756,7 +4765,7 @@ void AuraEffect::HandleForceReaction(AuraApplication const* aurApp, uint8 mode,
return;
uint32 factionId = GetMiscValue();
- ReputationRank factionRank = ReputationRank(m_amount);
+ ReputationRank factionRank = ReputationRank(GetAmount());
player->GetReputationMgr().ApplyForceReaction(factionId, factionRank, apply);
player->GetReputationMgr().SendForceReactions();
@@ -4836,7 +4845,7 @@ void AuraEffect::HandleAuraConvertRune(AuraApplication const* aurApp, uint8 mode
if (player->getClass() != CLASS_DEATH_KNIGHT)
return;
- uint32 runes = m_amount;
+ uint32 runes = GetAmount();
// convert number of runes specified in aura amount of rune type in miscvalue to runetype in miscvalueb
if (apply)
{
@@ -5060,7 +5069,10 @@ void AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick(Unit* target, Unit*
void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
{
- if (!caster || !target->IsAlive())
+ // dynobj auras must always have a caster
+ ASSERT(GetSpellInfo()->Effects[GetEffIndex()].Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA || caster);
+
+ if (!target->IsAlive())
return;
if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamage(GetSpellInfo()))
@@ -5076,104 +5088,100 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- // AOE spells are not affected by the new periodic system.
- bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
// ignore negative values (can be result apply spellmods to aura damage
- uint32 damage = std::max(GetAmount() + GetBonusAmount(), 0); // if isAreaAura == true, GetBonusAmount == 0.
+ uint32 damage = std::max(GetAmount(), 0);
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage);
if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE)
{
- if (isAreaAura)
- damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT);
- else
- damage = std::max(int32(damage * GetDonePct()), 0);
-
- if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
-
- damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
-
- // Calculate armor mitigation
- if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex()))
- {
- uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo());
- cleanDamage.mitigated_damage += damage - damageReductedArmor;
- damage = damageReductedArmor;
- }
+ // leave only target depending bonuses, rest is handled in calculate amount
+ if (GetBase()->GetType() == DYNOBJ_AURA_TYPE)
+ damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, { }, GetBase()->GetStackAmount());
- // Curse of Agony damage-per-tick calculation
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellInfo()->SpellFamilyFlags[0] & 0x400) && GetSpellInfo()->SpellIconID == 544)
- {
- uint32 totalTicks = GetTotalTicks();
- // 1..4 ticks, 1/2 from normal tick damage
- if (_ticksDone <= totalTicks / 3)
- damage = damage / 2;
- // 9..12 ticks, 3/2 from normal tick damage
- else if (_ticksDone > totalTicks * 2 / 3)
- damage += (damage + 1) / 2; // +1 prevent 0.5 damage possible lost at 1..4 ticks
- // 5..8 ticks have normal tick damage
- }
- // There is a Chance to make a Soul Shard when Drain soul does damage
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000))
+ switch (GetSpellInfo()->SpellFamilyName)
{
- if (caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target))
+ case SPELLFAMILY_WARLOCK:
{
- if (roll_chance_i(20))
+ // Curse of Agony damage-per-tick calculation
+ if ((GetSpellInfo()->SpellFamilyFlags[0] & 0x400) && GetSpellInfo()->SpellIconID == 544)
+ {
+ uint32 totalTicks = GetTotalTicks();
+ // 1..4 ticks, 1/2 from normal tick damage
+ if (_ticksDone <= totalTicks / 3)
+ damage = damage / 2;
+ // 9..12 ticks, 3/2 from normal tick damage
+ else if (_ticksDone > totalTicks * 2 / 3)
+ damage += (damage + 1) / 2; // +1 prevent 0.5 damage possible lost at 1..4 ticks
+ // 5..8 ticks have normal tick damage
+ }
+ // There is a Chance to make a Soul Shard when Drain soul does damage
+ else if ((GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000))
{
- caster->CastSpell(caster, 43836, this);
- // Glyph of Drain Soul - chance to create an additional Soul Shard
- if (AuraEffect* aur = caster->GetAuraEffect(58070, 0))
- if (roll_chance_i(aur->GetMiscValue()))
- caster->CastSpell(caster, 58068, aur);
+ if (caster && caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target))
+ {
+ if (roll_chance_i(20))
+ {
+ caster->CastSpell(caster, 43836, this);
+ // Glyph of Drain Soul - chance to create an additional Soul Shard
+ if (AuraEffect* aur = caster->GetAuraEffect(58070, 0))
+ if (roll_chance_i(aur->GetMiscValue()))
+ caster->CastSpell(caster, 58068, aur);
+ }
+ }
}
+ break;
}
- }
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_GENERIC)
- {
- switch (GetId())
+ case SPELLFAMILY_GENERIC:
{
- case 70911: // Unbound Plague
- case 72854: // Unbound Plague
- case 72855: // Unbound Plague
- case 72856: // Unbound Plague
- damage *= uint32(pow(1.25f, int32(_ticksDone)));
- break;
- default:
- break;
+ switch (GetId())
+ {
+ case 70911: // Unbound Plague
+ case 72854: // Unbound Plague
+ case 72855: // Unbound Plague
+ case 72856: // Unbound Plague
+ damage *= uint32(pow(1.25f, int32(_ticksDone)));
+ break;
+ default:
+ break;
+ }
+ break;
}
+ default:
+ break;
}
}
else // ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner
damage = uint32(ceil(CalculatePct<float, float>(target->GetMaxHealth(), damage)));
- if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
- {
- if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
- {
- damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
- if (caster->GetTypeId() != TYPEID_PLAYER)
- damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
- }
- }
+ damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
- bool crit = false;
+ bool crit = roll_chance_f(GetCritChanceFor(caster, target));
+ if (crit)
+ damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage, target);
- if (CanPeriodicTickCrit(caster))
- crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : GetCritChance());
+ // Calculate armor mitigation
+ if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex()))
+ {
+ uint32 damageReductedArmor = Unit::CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetBase()->GetCasterLevel());
+ cleanDamage.mitigated_damage += damage - damageReductedArmor;
+ damage = damageReductedArmor;
+ }
- if (crit)
- damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target);
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ {
+ if (GetSpellInfo()->Effects[GetEffIndex()].IsTargetingArea() || GetSpellInfo()->Effects[GetEffIndex()].IsAreaAuraEffect() || GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA)
+ damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, caster);
+ }
int32 dmg = damage;
- if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
- caster->ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL);
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE) && GetBase()->CanApplyResilience())
+ Unit::ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL);
damage = dmg;
DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
- caster->CalcAbsorbResist(damageInfo);
+ Unit::CalcAbsorbResist(damageInfo);
damage = damageInfo.GetDamage();
uint32 absorb = damageInfo.GetAbsorb();
@@ -5181,7 +5189,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s attacked %s for %u dmg inflicted by %u absorb is %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb);
- caster->DealDamageMods(target, damage, &absorb);
+ Unit::DealDamageMods(target, damage, &absorb);
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
@@ -5200,14 +5208,17 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
- caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
+ Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
- caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
+ Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
}
void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const
{
- if (!caster || !target->IsAlive())
+ // dynobj auras must always have a caster
+ ASSERT(GetSpellInfo()->Effects[GetEffIndex()].Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA || caster);
+
+ if (!target->IsAlive())
return;
if (target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsImmunedToDamage(GetSpellInfo()))
@@ -5222,56 +5233,41 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
// ignore negative values (can be result apply spellmods to aura damage
- uint32 damage = std::max(GetAmount() + GetBonusAmount(), 0); // if isAreaAura == true, GetBonusAmount == 0.
+ uint32 damage = std::max(GetAmount(), 0);
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage);
- if (isAreaAura)
- damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT);
- else
- damage = std::max(int32(damage * GetDonePct()), 0);
-
- if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
-
+ if (GetBase()->GetType() == DYNOBJ_AURA_TYPE)
+ damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, { }, GetBase()->GetStackAmount());
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
+ bool crit = roll_chance_f(GetCritChanceFor(caster, target));
+ if (crit)
+ damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage, target);
+
// Calculate armor mitigation
if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex()))
{
- uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo());
+ uint32 damageReductedArmor = Unit::CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetBase()->GetCasterLevel());
cleanDamage.mitigated_damage += damage - damageReductedArmor;
damage = damageReductedArmor;
}
- if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
{
- if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura)
- {
- damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
- if (caster->GetTypeId() != TYPEID_PLAYER)
- damage = uint32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
- }
+ if (GetSpellInfo()->Effects[GetEffIndex()].IsTargetingArea() || GetSpellInfo()->Effects[GetEffIndex()].IsAreaAuraEffect() || GetSpellInfo()->Effects[GetEffIndex()].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA)
+ damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, caster);
}
- bool crit = false;
-
- if (CanPeriodicTickCrit(caster))
- crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : GetCritChance());
-
- if (crit)
- damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target);
-
int32 dmg = damage;
- if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
- caster->ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL);
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE) && GetBase()->CanApplyResilience())
+ Unit::ApplyResilience(target, nullptr, &dmg, crit, CR_CRIT_TAKEN_SPELL);
damage = dmg;
DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
- caster->CalcAbsorbResist(damageInfo);
+ Unit::CalcAbsorbResist(damageInfo);
uint32 absorb = damageInfo.GetAbsorb();
uint32 resist = damageInfo.GetResist();
@@ -5292,22 +5288,22 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
}
- int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
- if (caster->IsAlive())
- {
- caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
+ int32 new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
+ if (!caster || !caster->IsAlive())
+ return;
- float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster);
+ Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
- uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetBase()->GetStackAmount()));
- heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount()));
+ float gainMultiplier = GetSpellInfo()->Effects[GetEffIndex()].CalcValueMultiplier(caster);
- HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
- caster->HealBySpell(healInfo);
+ uint32 heal = caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, { }, GetBase()->GetStackAmount());
+ heal = caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetBase()->GetStackAmount());
- caster->GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal()*0.5f, GetSpellInfo());
- caster->ProcSkillsAndAuras(caster, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
- }
+ HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
+ caster->HealBySpell(healInfo);
+
+ caster->GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
+ Unit::ProcSkillsAndAuras(caster, caster, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const
@@ -5337,12 +5333,15 @@ void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster)
HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
caster->HealBySpell(healInfo);
- caster->ProcSkillsAndAuras(target, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, PROC_HIT_NORMAL, nullptr, nullptr, &healInfo);
+ Unit::ProcSkillsAndAuras(caster, target, PROC_FLAG_DONE_PERIODIC, PROC_FLAG_TAKEN_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, PROC_HIT_NORMAL, nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
{
- if (!caster || !target->IsAlive())
+ // dynobj auras must always have a caster
+ ASSERT(GetSpellInfo()->Effects[GetEffIndex()].Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA || caster);
+
+ if (!target->IsAlive())
return;
if (target->HasUnitState(UNIT_STATE_ISOLATED))
@@ -5352,72 +5351,32 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
}
// heal for caster damage (must be alive)
- if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL) && !caster->IsAlive())
+ if (target != caster && GetSpellInfo()->HasAttribute(SPELL_ATTR2_HEALTH_FUNNEL) && (!caster || !caster->IsAlive()))
return;
// don't regen when permanent aura target has full power
if (GetBase()->IsPermanent() && target->IsFullHealth())
return;
- bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
// ignore negative values (can be result apply spellmods to aura damage
- uint32 damage = std::max(GetAmount() + GetBonusAmount(), 0); // if isAreaAura == true, GetBonusAmount == 0.
+ uint32 damage = std::max(GetAmount(), 0);
// Script Hook For HandlePeriodicHealAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage);
if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH)
- {
- // Taken mods
- float TakenTotalMod = 1.0f;
-
- // Tenacity increase healing % taken
- if (AuraEffect const* Tenacity = target->GetAuraEffect(58549, 0))
- AddPct(TakenTotalMod, Tenacity->GetAmount());
-
- // Healing taken percent
- float minval = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
- if (minval)
- AddPct(TakenTotalMod, minval);
-
- float maxval = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
- if (maxval)
- AddPct(TakenTotalMod, maxval);
-
- // Healing over time taken percent
- float minval_hot = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT);
- if (minval_hot)
- AddPct(TakenTotalMod, minval_hot);
-
- float maxval_hot = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT);
- if (maxval_hot)
- AddPct(TakenTotalMod, maxval_hot);
-
- TakenTotalMod = std::max(TakenTotalMod, 0.0f);
-
damage = uint32(target->CountPctFromMaxHealth(damage));
- damage = uint32(damage * TakenTotalMod);
- }
else
{
- if (isAreaAura)
- damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellHealingPctDone(target, m_spellInfo);
- else
- damage = std::max(int32(damage * GetDonePct()), 0);
-
- if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
-
- damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
+ if (GetBase()->GetType() == DYNOBJ_AURA_TYPE)
+ damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, { }, GetBase()->GetStackAmount());
}
- bool crit = false;
-
- if (CanPeriodicTickCrit(caster))
- crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : GetCritChance());
+ damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
+ bool crit = roll_chance_f(GetCritChanceFor(caster, target));
if (crit)
- damage = caster->SpellCriticalHealingBonus(m_spellInfo, damage, target);
+ damage = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, damage, target);
TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s heal of %s for %u health inflicted by %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId());
@@ -5425,13 +5384,14 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
uint32 heal = damage;
HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
- caster->CalcHealAbsorb(healInfo);
- caster->DealHeal(healInfo);
+ Unit::CalcHealAbsorb(healInfo);
+ Unit::DealHeal(healInfo);
SpellPeriodicAuraLogInfo pInfo(this, heal, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
- target->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo.GetEffectiveHeal())*0.5f, GetSpellInfo());
+ if (caster)
+ target->GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
bool haveCastItem = !GetBase()->GetCastItemGUID().IsEmpty();
@@ -5445,11 +5405,11 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
funnelDamage = healInfo.GetEffectiveHeal();
uint32 funnelAbsorb = 0;
- caster->DealDamageMods(caster, funnelDamage, &funnelAbsorb);
+ Unit::DealDamageMods(caster, funnelDamage, &funnelAbsorb);
caster->SendSpellNonMeleeDamageLog(caster, GetId(), funnelDamage, GetSpellInfo()->GetSchoolMask(), funnelAbsorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- caster->DealDamage(caster, funnelDamage, &cleanDamage, NODAMAGE, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
+ Unit::DealDamage(caster, caster, funnelDamage, &cleanDamage, SELF_DAMAGE, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
}
// %-based heal - does not proc auras
@@ -5461,7 +5421,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
// ignore item heals
if (!haveCastItem)
- caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
+ Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const
@@ -5482,7 +5442,7 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con
return;
// ignore negative values (can be result apply spellmods to aura damage
- int32 drainAmount = std::max(m_amount, 0);
+ int32 drainAmount = std::max(GetAmount(), 0);
// Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana)
// It's mana percent cost spells, m_amount is percent drain from target
@@ -5559,7 +5519,7 @@ void AuraEffect::HandleObsModPowerAuraTick(Unit* target, Unit* caster) const
return;
// ignore negative values (can be result apply spellmods to aura damage
- uint32 amount = std::max(m_amount, 0) * target->GetMaxPower(powerType) /100;
+ uint32 amount = std::max(GetAmount(), 0) * target->GetMaxPower(powerType) /100;
TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s energize %s for %u dmg inflicted by %u",
GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), amount, GetId());
@@ -5593,7 +5553,7 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons
return;
// ignore negative values (can be result apply spellmods to aura damage
- int32 amount = std::max(m_amount, 0);
+ int32 amount = std::max(GetAmount(), 0);
SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false);
target->SendPeriodicAuraLog(&pInfo);
@@ -5621,7 +5581,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
}
// ignore negative values (can be result apply spellmods to aura damage
- int32 damage = std::max(m_amount, 0);
+ int32 damage = std::max(GetAmount(), 0);
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
if (powerType == POWER_MANA)
@@ -5637,7 +5597,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
// no SpellDamageBonus for burn mana
caster->CalculateSpellDamageTaken(&damageInfo, int32(gain * dmgMultiplier), spellProto);
- caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
+ Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
caster->SendSpellNonMeleeDamageLog(&damageInfo);
@@ -5655,7 +5615,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
caster->DealSpellDamage(&damageInfo, true);
DamageInfo dotDamageInfo(damageInfo, DOT, BASE_ATTACK, hitMask);
- caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dotDamageInfo, nullptr);
+ Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dotDamageInfo, nullptr);
}
void AuraEffect::HandleModAttackPowerOfArmorAuraTick(Unit* target, Unit* caster) const
@@ -5723,10 +5683,10 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv
}
SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetSpellInfo()->SchoolMask);
- uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE);
+ uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, { });
damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE);
target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellInfo());
- target->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
+ Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
target->SendSpellNonMeleeDamageLog(&damageInfo);
TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerDamageAuraProc: Triggering %u spell damage from aura %u proc", damage, GetId());
target->DealSpellDamage(&damageInfo, true);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index befe0d7a2f6..1818dc359af 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -55,8 +55,8 @@ class TC_GAME_API AuraEffect
int32 GetMiscValueB() const { return m_spellInfo->Effects[m_effIndex].MiscValueB; }
int32 GetMiscValue() const { return m_spellInfo->Effects[m_effIndex].MiscValue; }
AuraType GetAuraType() const { return (AuraType)m_spellInfo->Effects[m_effIndex].ApplyAuraName; }
- int32 GetAmount() const { return m_amount; }
- void SetAmount(int32 amount) { m_amount = amount; m_canBeRecalculated = false;}
+ int32 GetAmount() const { return _amount; }
+ void SetAmount(int32 amount) { _amount = amount; m_canBeRecalculated = false; }
int32 GetPeriodicTimer() const { return _periodicTimer; }
void SetPeriodicTimer(int32 periodicTimer) { _periodicTimer = periodicTimer; }
@@ -73,13 +73,6 @@ class TC_GAME_API AuraEffect
void HandleEffect(Unit* target, uint8 mode, bool apply);
void ApplySpellMod(Unit* target, bool apply);
- void SetBonusAmount(int32 val) { m_bonusAmount = val; }
- int32 GetBonusAmount() const { return m_bonusAmount; }
- void SetCritChance(float val) { m_critChance = val; }
- float GetCritChance() const { return m_critChance; }
- void SetDonePct(float val) { m_donePct = val; }
- float GetDonePct() const { return m_donePct; }
-
void Update(uint32 diff, Unit* caster);
uint32 GetTickNumber() const { return _ticksDone; }
@@ -109,10 +102,7 @@ class TC_GAME_API AuraEffect
SpellInfo const* const m_spellInfo;
int32 const m_baseAmount;
- int32 m_amount;
- int32 m_bonusAmount;
- float m_critChance;
- float m_donePct;
+ int32 _amount;
SpellModifier* m_spellmod;
@@ -124,8 +114,8 @@ class TC_GAME_API AuraEffect
uint8 const m_effIndex;
bool m_canBeRecalculated;
bool m_isPeriodic;
- private:
- bool CanPeriodicTickCrit(Unit const* caster) const;
+
+ float GetCritChanceFor(Unit const* caster, Unit const* target) const;
public:
// aura effect apply/remove handlers
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index d1285e5633c..5d34233fc00 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -344,7 +344,7 @@ Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item*
m_spellInfo(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID()),
m_castItemGuid(castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_applyTime(GameTime::GetGameTime()),
m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0),
-m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1),
+_casterInfo(), m_procCharges(0), m_stackAmount(1),
m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr),
m_procCooldown(std::chrono::steady_clock::time_point::min())
{
@@ -356,7 +356,15 @@ m_procCooldown(std::chrono::steady_clock::time_point::min())
m_procCharges = CalcMaxCharges(caster);
m_isUsingCharges = m_procCharges != 0;
memset(m_effects, 0, sizeof(m_effects));
+
// m_casterLevel = cast item level/caster level, caster level should be saved to db, confirmed with sniffs
+ _casterInfo.Level = m_spellInfo->SpellLevel;
+ if (caster)
+ {
+ _casterInfo.Level = caster->getLevel();
+ _casterInfo.ApplyResilience = caster->CanApplyResilience();
+ SaveCasterInfo(caster);
+ }
}
AuraScript* Aura::GetScriptByName(std::string const& scriptName) const
@@ -379,6 +387,58 @@ void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount)
}
}
+bool Aura::CanPeriodicTickCrit(Unit const* caster) const
+{
+ if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, GetSpellInfo()))
+ return true;
+
+ // Rupture - since 3.3.3 can crit
+ if (GetSpellInfo()->SpellIconID == 500 && GetSpellInfo()->SpellFamilyName == SPELLFAMILY_ROGUE)
+ return true;
+
+ return false;
+}
+
+float Aura::CalcPeriodicCritChance(Unit const* caster) const
+{
+ Player* modOwner = caster->GetSpellModOwner();
+ if (!modOwner || !CanPeriodicTickCrit(modOwner))
+ return 0.f;
+
+ float critChance = modOwner->SpellCritChanceDone(GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), GetSpellInfo()->GetAttackType());
+ return std::max(0.f, critChance);
+}
+
+void Aura::SaveCasterInfo(Unit* caster)
+{
+ _casterInfo.CritChance = CalcPeriodicCritChance(caster);
+
+ if (GetType() == UNIT_AURA_TYPE)
+ {
+ /*
+ * Get critical chance from last effect type (damage or healing)
+ * this could potentialy be wrong if any spell has both damage and heal periodics
+ * The only two spells in 3.3.5 with those conditions are 17484 and 50344
+ * which shouldn't be allowed to crit, so we're fine
+ */
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ switch (GetSpellInfo()->Effects[i].ApplyAuraName)
+ {
+ case SPELL_AURA_PERIODIC_HEAL:
+ _casterInfo.BonusDonePct = caster->SpellHealingPctDone(GetUnitOwner(), GetSpellInfo());
+ break;
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_PERIODIC_LEECH:
+ _casterInfo.BonusDonePct = caster->SpellDamagePctDone(GetUnitOwner(), GetSpellInfo(), DOT);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
Aura::~Aura()
{
// unload scripts
@@ -870,13 +930,8 @@ void Aura::SetStackAmount(uint8 stackAmount)
m_effects[i]->ChangeAmount(m_effects[i]->CalculateAmount(caster), false, true);
for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr)
- {
if (!(*apptItr)->GetRemoveMode())
- {
- HandleAuraSpecificPeriodics(*apptItr, caster);
HandleAuraSpecificMods(*apptItr, caster, true, true);
- }
- }
SetNeedClientUpdateForTargets();
}
@@ -1067,13 +1122,15 @@ int32 Aura::CalcDispelChance(Unit const* auraTarget, bool offensive) const
return 100 - resistChance;
}
-void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount)
+void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, float critChance, bool applyResilience, int32* amount)
{
m_maxDuration = maxduration;
m_duration = duration;
m_procCharges = charges;
m_isUsingCharges = m_procCharges != 0;
m_stackAmount = stackamount;
+ SetCritChance(critChance);
+ SetCanApplyResilience(applyResilience);
Unit* caster = GetCaster();
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
@@ -1307,10 +1364,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// Improved Devouring Plague
if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 1))
{
- int32 damage = (devouringPlague->GetAmount() + devouringPlague->GetBonusAmount()) * devouringPlague->GetDonePct();
- if (Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, damage);
-
+ int32 damage = devouringPlague->GetAmount();
damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT);
CastSpellExtraArgs args(devouringPlague), args2(devouringPlague);
@@ -1672,50 +1726,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
}
}
-void Aura::HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* caster)
-{
- Unit* target = aurApp->GetTarget();
-
- if (!caster || aurApp->GetRemoveMode())
- return;
-
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if (!HasEffect(i))
- continue;
-
- if (m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA))
- continue;
-
- switch (m_spellInfo->Effects[i].ApplyAuraName)
- {
- case SPELL_AURA_PERIODIC_DAMAGE:
- case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
- case SPELL_AURA_PERIODIC_LEECH:
- {
- AuraEffect* aurEff = GetEffect(i);
-
- aurEff->SetDonePct(caster->SpellDamagePctDone(target, m_spellInfo, DOT));
- aurEff->SetBonusAmount(caster->SpellDamageBonusDone(target, m_spellInfo, 0, DOT, GetStackAmount()));
- aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()));
- break;
- }
- case SPELL_AURA_PERIODIC_HEAL:
- case SPELL_AURA_OBS_MOD_HEALTH:
- {
- AuraEffect* aurEff = GetEffect(i);
-
- aurEff->SetDonePct(caster->SpellHealingPctDone(target, m_spellInfo));
- aurEff->SetBonusAmount(caster->SpellHealingBonusDone(target, m_spellInfo, 0, DOT, GetStackAmount()));
- aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()));
- break;
- }
- default:
- break;
- }
- }
-}
-
bool Aura::CanBeAppliedOn(Unit* target)
{
// unit not in world or during remove from world
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index c99f9f1a73a..82613cea9ea 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -82,6 +82,15 @@ class TC_GAME_API AuraApplication
void ClientUpdate(bool remove = false);
};
+// Caches some information about caster (because it may no longer exist)
+struct CasterInfo
+{
+ float CritChance = 0.f;
+ float BonusDonePct = 0.f;
+ uint8 Level = 0;
+ bool ApplyResilience = false;
+};
+
class TC_GAME_API Aura
{
friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, bool resetPeriodicTimer);
@@ -94,6 +103,7 @@ class TC_GAME_API Aura
static Aura* Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID);
explicit Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID);
void _InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount);
+ void SaveCasterInfo(Unit* caster);
virtual ~Aura();
SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
@@ -148,7 +158,13 @@ class TC_GAME_API Aura
void SetStackAmount(uint8 num);
bool ModStackAmount(int32 num, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer = true);
- uint8 GetCasterLevel() const { return m_casterLevel; }
+ bool CanApplyResilience() const { return _casterInfo.ApplyResilience; }
+ void SetCanApplyResilience(bool val) { _casterInfo.ApplyResilience = val; }
+ uint8 GetCasterLevel() const { return _casterInfo.Level; }
+ float GetCritChance() const { return _casterInfo.CritChance; }
+ void SetCritChance(float val) { _casterInfo.CritChance = val; }
+ float GetDonePct() const { return _casterInfo.BonusDonePct; }
+ void SetDonePct(float val) { _casterInfo.BonusDonePct = val; }
bool HasMoreThanOneEffectForType(AuraType auraType) const;
bool IsArea() const;
@@ -173,9 +189,12 @@ class TC_GAME_API Aura
void UnregisterSingleTarget();
int32 CalcDispelChance(Unit const* auraTarget, bool offensive) const;
- void SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount);
+ void SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, float critChance, bool applyResilience, int32* amount);
// helpers for aura effects
+ bool CanPeriodicTickCrit(Unit const* caster) const;
+ float CalcPeriodicCritChance(Unit const* caster) const;
+
bool HasEffect(uint8 effIndex) const { return GetEffect(effIndex) != nullptr; }
bool HasEffectType(AuraType type) const;
AuraEffect* GetEffect(uint8 effIndex) const { ASSERT (effIndex < MAX_SPELL_EFFECTS); return m_effects[effIndex]; }
@@ -192,7 +211,6 @@ class TC_GAME_API Aura
void SetNeedClientUpdateForTargets() const;
void HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, bool apply, bool onReapply);
- void HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* caster);
bool CanBeAppliedOn(Unit* target);
bool CheckAreaTarget(Unit* target);
bool CanStackWith(Aura const* existingAura) const;
@@ -258,7 +276,7 @@ class TC_GAME_API Aura
int32 m_timeCla; // Timer for power per sec calcultion
int32 m_updateTargetMapInterval; // Timer for UpdateTargetMapOfEffect
- uint8 const m_casterLevel; // Aura level (store caster level for correct show level dep amount)
+ CasterInfo _casterInfo;
uint8 m_procCharges; // Aura charges (0 for infinite)
uint8 m_stackAmount; // Aura stack amount
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 184a003cba0..8fd6715bf24 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2017,7 +2017,7 @@ class ProcReflectDelayed : public BasicEvent
uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE;
uint32 const hitMask = PROC_HIT_REFLECT;
- caster->ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
+ Unit::ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
return true;
}
@@ -2394,7 +2394,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (crit)
{
hitMask |= PROC_HIT_CRITICAL;
- addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, nullptr);
+ addhealth = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, addhealth, nullptr);
}
else
hitMask |= PROC_HIT_NORMAL;
@@ -2406,7 +2406,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Do triggers for unit
if (canEffectTrigger)
- caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo);
+ Unit::ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo);
}
// Do damage and triggers
else if (m_damage > 0)
@@ -2426,7 +2426,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
{
// Add bonuses and fill damageInfo struct
caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit);
- caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
+ Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
@@ -2442,7 +2442,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (canEffectTrigger)
{
DamageInfo spellDamageInfo(damageInfo, SPELL_DIRECT_DAMAGE, m_attackType, hitMask);
- caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr);
+ Unit::ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, this, &spellDamageInfo, nullptr);
if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) && !m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS) &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
@@ -2459,7 +2459,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (canEffectTrigger)
{
DamageInfo spellNoDamageInfo(damageInfo, NODAMAGE, m_attackType, hitMask);
- caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr);
+ Unit::ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_NO_DMG_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, &spellNoDamageInfo, nullptr);
if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) && !m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS) &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
@@ -3379,7 +3379,7 @@ void Spell::_cast(bool skipCheck)
if (!(hitMask & PROC_HIT_CRITICAL))
hitMask |= PROC_HIT_NORMAL;
- m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
+ Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
}
void Spell::handle_immediate()
@@ -3575,7 +3575,7 @@ void Spell::_handle_finish_phase()
procAttacker = IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
}
- m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, m_hitMask, this, nullptr, nullptr);
+ Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_FINISH, m_hitMask, this, nullptr, nullptr);
}
void Spell::SendSpellCooldown()
@@ -7308,9 +7308,7 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier)
{
if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA))
{
- m_damage = int32(float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
- if (m_caster->GetTypeId() != TYPEID_PLAYER)
- m_damage = int32(float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask));
+ m_damage = unit->CalculateAOEAvoidance(m_damage, m_spellInfo->SchoolMask, m_caster);
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
@@ -7330,7 +7328,8 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier)
}
}
- targetInfo.crit = m_caster->IsSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType);
+ float critChance = m_caster->SpellCritChanceDone(m_spellInfo, m_spellSchoolMask, m_attackType);
+ targetInfo.crit = roll_chance_f(unit->SpellCritChanceTaken(m_caster, m_spellInfo, m_spellSchoolMask, critChance, m_attackType));
}
SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 5baf98ebf10..2e43d43bd81 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -286,7 +286,7 @@ void Spell::EffectInstaKill(SpellEffIndex /*effIndex*/)
data << uint32(m_spellInfo->Id);
m_caster->SendMessageToSet(&data, true);
- m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
+ Unit::DealDamage(m_caster, unitTarget, unitTarget->GetHealth(), nullptr, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
}
void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/)
@@ -303,7 +303,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/)
else
{
DamageInfo damageInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
- m_caster->CalcAbsorbResist(damageInfo);
+ Unit::CalcAbsorbResist(damageInfo);
uint32 absorb = damageInfo.GetAbsorb();
uint32 resist = damageInfo.GetResist();
@@ -430,10 +430,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
if (aura)
{
// Calculate damage of Immolate/Shadowflame tick
- int32 pdamage = (aura->GetAmount() + aura->GetBonusAmount()) * aura->GetDonePct();
- if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_DOT, pdamage);
-
+ int32 pdamage = aura->GetAmount();
pdamage = unitTarget->SpellDamageBonusTaken(m_caster, aura->GetSpellInfo(), pdamage, DOT);
// And multiply by amount of ticks to get damage potential
@@ -670,7 +667,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
if (m_originalCaster && damage > 0 && apply_direct_bonus)
{
- damage = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
+ damage = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, { });
damage = unitTarget->SpellDamageBonusTaken(m_originalCaster, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
}
@@ -1210,7 +1207,7 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex)
return;
// add spell damage bonus
- damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
+ damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, { });
damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
@@ -1372,10 +1369,7 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
return;
}
- int32 tickheal = (targetAura->GetAmount() + targetAura->GetBonusAmount()) * targetAura->GetDonePct();
- if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(targetAura->GetId(), SPELLMOD_DOT, tickheal);
-
+ int32 tickheal = targetAura->GetAmount();
unitTarget->SpellHealingBonusTaken(m_caster, targetAura->GetSpellInfo(), tickheal, DOT);
//int32 tickheal = targetAura->GetSpellInfo()->EffectBasePoints[idx] + 1;
@@ -1401,24 +1395,27 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
// Nourish
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x2000000)
{
- addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL);
+ addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, { });
// Glyph of Nourish
if (AuraEffect const* aurEff = m_caster->GetAuraEffect(62971, 0))
{
- Unit::AuraEffectList const& Periodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL);
- for (Unit::AuraEffectList::const_iterator i = Periodic.begin(); i != Periodic.end(); ++i)
+ uint32 auraCount = 0;
+ Unit::AuraEffectList const& periodicHeals = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL);
+ for (AuraEffect const* hot : periodicHeals)
{
- if (m_caster->GetGUID() == (*i)->GetCasterGUID())
- AddPct(addhealth, aurEff->GetAmount());
+ if (m_caster->GetGUID() == hot->GetCasterGUID())
+ ++auraCount;
}
+
+ AddPct(addhealth, aurEff->GetAmount() * auraCount);
}
}
// Death Pact - return pct of max health to caster
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000)
- addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL);
+ addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL, { });
else
- addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL);
+ addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, { });
addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL);
@@ -1442,10 +1439,8 @@ void Spell::EffectHealPct(SpellEffIndex /*effIndex*/)
if (!m_originalCaster)
return;
- uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL);
- heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
-
- m_healing += heal;
+ uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL, { });
+ m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
}
void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/)
@@ -1460,8 +1455,7 @@ void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/)
if (!m_originalCaster)
return;
- uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL);
-
+ uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL, { });
m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
}
@@ -1473,7 +1467,7 @@ void Spell::EffectHealthLeech(SpellEffIndex effIndex)
if (!unitTarget || !unitTarget->IsAlive() || damage < 0)
return;
- damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
+ damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, { });
damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
TC_LOG_DEBUG("spells", "HealthLeech :%i", damage);
@@ -1486,7 +1480,7 @@ void Spell::EffectHealthLeech(SpellEffIndex effIndex)
if (m_caster->IsAlive())
{
- healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL);
+ healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL, { });
healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL);
HealInfo healInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellSchoolMask);
@@ -3406,7 +3400,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex)
{
int32 duration = m_spellInfo->GetDuration();
unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
- m_originalCaster->ProcSkillsAndAuras(unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr);
+ Unit::ProcSkillsAndAuras(m_originalCaster, unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr);
}
ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 274d77c0134..731d4f4dfb7 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2977,6 +2977,21 @@ void SpellMgr::LoadSpellInfoCorrections()
});
}
+ // Allows those to crit
+ ApplySpellFix({
+ 379, // Earth Shield
+ 33778, // Lifebloom Final Bloom
+ 64844, // Divine Hymn
+ 71607, // Item - Bauble of True Blood 10m
+ 71646, // Item - Bauble of True Blood 25m
+ 71610, // Item - Althor's Abacus trigger 10m
+ 71641 // Item - Althor's Abacus trigger 25m
+ }, [](SpellInfo* spellInfo)
+ {
+ // We need more spells to find a general way (if there is any)
+ spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC;
+ });
+
// Spell Reflection
ApplySpellFix({ 57643 }, [](SpellInfo* spellInfo)
{
@@ -3172,6 +3187,14 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS);
});
+ // Arcane Potency
+ ApplySpellFix({ 57529, 57531 }, [](SpellInfo* spellInfo)
+ {
+ spellInfo->Effects[EFFECT_0].SpellClassMask = flag96();
+ spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER;
+ spellInfo->Effects[EFFECT_0].MiscValue = SPELLMOD_CRITICAL_CHANCE;
+ });
+
ApplySpellFix({
44978, // Wild Magic
45001, // Wild Magic