aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp9
-rw-r--r--src/server/game/DataStores/DB2Stores.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp264
-rw-r--r--src/server/game/Entities/Player/Player.h26
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp1093
-rw-r--r--src/server/game/Entities/Unit/Unit.h313
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h4
-rw-r--r--src/server/game/Spells/Auras/SpellAuraDefines.h10
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp293
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h8
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp120
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h11
-rw-r--r--src/server/game/Spells/Spell.cpp222
-rw-r--r--src/server/game/Spells/Spell.h6
-rw-r--r--src/server/game/Spells/SpellEffects.cpp3
-rw-r--r--src/server/game/Spells/SpellMgr.cpp618
-rw-r--r--src/server/game/Spells/SpellMgr.h62
-rw-r--r--src/server/game/Spells/SpellScript.cpp16
-rw-r--r--src/server/game/Spells/SpellScript.h17
-rw-r--r--src/server/game/World/World.cpp3
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp10
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp7
-rw-r--r--src/server/scripts/Spells/spell_item.cpp5
-rw-r--r--src/server/scripts/Spells/spell_mage.cpp4
-rw-r--r--src/server/scripts/Spells/spell_shaman.cpp7
26 files changed, 1160 insertions, 1974 deletions
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index a42d20c3cfb..5cbb1a3d093 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -603,7 +603,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695,
RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 696,
RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 697,
- RBAC_PERM_COMMAND_RELOAD_SPELL_PROC_EVENT = 698,
+ // 698 - reuse
RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 699,
RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS = 700,
RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION = 701,
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 830144965c4..7fca76949d5 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -344,6 +344,7 @@ namespace
RulesetItemUpgradeContainer _rulesetItemUpgrade;
SkillRaceClassInfoContainer _skillRaceClassInfoBySkill;
SpecializationSpellsContainer _specializationSpellsBySpec;
+ std::unordered_set<uint8> _spellFamilyNames;
SpellPowerContainer _spellPowers;
SpellPowerDifficultyContainer _spellPowerDifficulties;
SpellProcsPerMinuteModContainer _spellProcsPerMinuteMods;
@@ -936,6 +937,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
for (SpecializationSpellsEntry const* specSpells : sSpecializationSpellsStore)
_specializationSpellsBySpec[specSpells->SpecID].push_back(specSpells);
+ for (SpellClassOptionsEntry const* classOption : sSpellClassOptionsStore)
+ _spellFamilyNames.insert(classOption->SpellClassSet);
+
for (SpellPowerEntry const* power : sSpellPowerStore)
{
if (SpellPowerDifficultyEntry const* powerDifficulty = sSpellPowerDifficultyStore.LookupEntry(power->ID))
@@ -1868,6 +1872,11 @@ std::vector<SpecializationSpellsEntry const*> const* DB2Manager::GetSpecializati
return nullptr;
}
+bool DB2Manager::IsValidSpellFamiliyName(SpellFamilyNames family)
+{
+ return _spellFamilyNames.count(family) > 0;
+}
+
std::vector<SpellPowerEntry const*> DB2Manager::GetSpellPowers(uint32 spellId, Difficulty difficulty /*= DIFFICULTY_NONE*/, bool* hasDifficultyPowers /*= nullptr*/) const
{
std::vector<SpellPowerEntry const*> powers;
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 517cf8ae70a..3fbe1cb41c3 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -304,6 +304,7 @@ public:
uint32 GetRulesetItemUpgrade(uint32 itemId) const;
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId) const;
+ static bool IsValidSpellFamiliyName(SpellFamilyNames family);
std::vector<SpellPowerEntry const*> GetSpellPowers(uint32 spellId, Difficulty difficulty = DIFFICULTY_NONE, bool* hasDifficultyPowers = nullptr) const;
std::vector<SpellProcsPerMinuteModEntry const*> GetSpellProcsPerMinuteMods(uint32 spellprocsPerMinuteId) const;
std::vector<TalentEntry const*> const& GetTalentsByPosition(uint32 class_, uint32 tier, uint32 column) const;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 4da32995924..4ca84251276 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -7825,8 +7825,9 @@ void Player::ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const
}
-void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
+void Player::CastItemCombatSpell(DamageInfo const& damageInfo)
{
+ Unit* target = damageInfo.GetVictim();
if (!target || !target->IsAlive() || target == this)
return;
@@ -7834,7 +7835,9 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
{
// If usable, try to cast item spell
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (!item->IsBroken() && CanUseAttackType(attType))
+ {
+ if (!item->IsBroken() && CanUseAttackType(damageInfo.GetAttackType()))
+ {
if (ItemTemplate const* proto = item->GetTemplate())
{
// Additional check for weapons
@@ -7842,30 +7845,42 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
{
// offhand item cannot proc from main hand hit etc
EquipmentSlots slot;
- switch (attType)
+ switch (damageInfo.GetAttackType())
{
- case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
- case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
- case RANGED_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
- default: slot = EQUIPMENT_SLOT_END; break;
+ case BASE_ATTACK:
+ slot = EQUIPMENT_SLOT_MAINHAND;
+ break;
+ case OFF_ATTACK:
+ slot = EQUIPMENT_SLOT_OFFHAND;
+ break;
+ case RANGED_ATTACK:
+ slot = EQUIPMENT_SLOT_MAINHAND;
+ break;
+ default:
+ slot = EQUIPMENT_SLOT_END;
+ break;
}
if (slot != i)
continue;
// Check if item is useable (forms or disarm)
- if (attType == BASE_ATTACK)
+ if (damageInfo.GetAttackType() == BASE_ATTACK)
if (!IsUseEquipedWeapon(true) && !IsInFeralForm())
continue;
}
- CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
+
+ CastItemCombatSpell(damageInfo, item, proto);
}
+ }
+ }
}
}
-void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto)
+void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto)
{
// Can do effect if any damage done to target
- if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
- //if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
+ // for done procs allow normal + critical + absorbs by default
+ bool canTrigger = (damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)) != 0;
+ if (canTrigger)
{
for (uint8 i = 0; i < proto->Effects.size(); ++i)
{
@@ -7891,14 +7906,14 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (proto->SpellPPMRate)
{
- uint32 WeaponSpeed = GetBaseAttackTime(attType);
+ uint32 WeaponSpeed = GetBaseAttackTime(damageInfo.GetAttackType());
chance = GetPPMProcChance(WeaponSpeed, proto->SpellPPMRate, spellInfo);
}
else if (chance > 100.0f)
chance = GetWeaponProcChance();
if (roll_chance_f(chance))
- CastSpell(target, spellInfo->Id, true, item);
+ CastSpell(damageInfo.GetVictim(), spellInfo->Id, true, item);
}
}
@@ -7916,18 +7931,17 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
continue;
SpellEnchantProcEntry const* entry = sSpellMgr->GetSpellEnchantProcEvent(enchant_id);
-
if (entry && entry->procEx)
{
// Check hit/crit/dodge/parry requirement
- if ((entry->procEx & procEx) == 0)
+ if ((entry->procEx & damageInfo.GetHitMask()) == 0)
continue;
}
else
{
// Can do effect if any damage done to target
- if (!(procVictim & PROC_FLAG_TAKEN_DAMAGE))
- //if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
+ // for done procs allow normal + critical + absorbs by default
+ if (!canTrigger)
continue;
}
@@ -7961,7 +7975,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (spellInfo->IsPositive())
CastSpell(this, spellInfo, true, item);
else
- CastSpell(target, spellInfo, true, item);
+ CastSpell(damageInfo.GetVictim(), spellInfo, true, item);
}
}
}
@@ -21422,13 +21436,13 @@ void Player::SendRemoveControlBar() const
GetSession()->SendPacket(packet.Write());
}
-bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell) const
+bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell)
{
if (!mod || !spellInfo)
return false;
- // Mod out of charges
- if (spell && mod->charges == -1 && spell->m_appliedMods.find(mod->ownerAura) == spell->m_appliedMods.end())
+ // First time this aura applies a mod to us and is out of charges
+ if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura))
return false;
// +duration to infinite duration spells making them limited
@@ -21439,7 +21453,7 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod
}
template <class T>
-void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell /*= nullptr*/)
+void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell /*= nullptr*/) const
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
@@ -21452,29 +21466,71 @@ void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* s
if (m_spellModTakingSpell)
spell = m_spellModTakingSpell;
- for (SpellModList::iterator itr = m_spellMods[op][SPELLMOD_FLAT].begin(); itr != m_spellMods[op][SPELLMOD_FLAT].end(); ++itr)
+ switch (op)
{
- SpellModifier* mod = *itr;
+ // special case, if a mod makes spell instant, only consume that mod
+ case SPELLMOD_CASTING_TIME:
+ {
+ SpellModifier* modInstantSpell = nullptr;
+ for (SpellModifier* mod : m_spellMods[op][SPELLMOD_PCT])
+ {
+ if (!IsAffectedBySpellmod(spellInfo, mod, spell))
+ continue;
+
+ if (basevalue < T(10000) && mod->value <= -100)
+ {
+ modInstantSpell = mod;
+ break;
+ }
+ }
+
+ if (modInstantSpell)
+ {
+ Player::ApplyModToSpell(modInstantSpell, spell);
+ basevalue = T(0);
+ return;
+ }
+ break;
+ }
+ // special case if two mods apply 100% critical chance, only consume one
+ case SPELLMOD_CRITICAL_CHANCE:
+ {
+ SpellModifier* modCritical = nullptr;
+ for (SpellModifier* mod : m_spellMods[op][SPELLMOD_FLAT])
+ {
+ if (!IsAffectedBySpellmod(spellInfo, mod, spell))
+ continue;
- // Charges can be set only for mods with auras
- if (!mod->ownerAura)
- ASSERT(mod->charges == 0);
+ if (mod->value >= 100)
+ {
+ modCritical = mod;
+ break;
+ }
+ }
+ if (modCritical)
+ {
+ Player::ApplyModToSpell(modCritical, spell);
+ basevalue = T(100);
+ return;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ for (SpellModifier* mod : m_spellMods[op][SPELLMOD_FLAT])
+ {
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
continue;
totalflat += mod->value;
- DropModCharge(mod, spell);
+ Player::ApplyModToSpell(mod, spell);
}
- for (SpellModList::iterator itr = m_spellMods[op][SPELLMOD_PCT].begin(); itr != m_spellMods[op][SPELLMOD_PCT].end(); ++itr)
+ for (SpellModifier* mod : m_spellMods[op][SPELLMOD_PCT])
{
- SpellModifier* mod = *itr;
-
- // Charges can be set only for mods with auras
- if (!mod->ownerAura)
- ASSERT(mod->charges == 0);
-
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
continue;
@@ -21483,19 +21539,22 @@ void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* s
continue;
// special case (skip > 10sec spell casts for instant cast setting)
- if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100)
- continue;
+ if (op == SPELLMOD_CASTING_TIME)
+ {
+ if (basevalue >= T(10000) && mod->value <= -100)
+ continue;
+ }
totalmul *= 1.0f + CalculatePct(1.0f, mod->value);
- DropModCharge(mod, spell);
+ Player::ApplyModToSpell(mod, spell);
}
basevalue = T(float(basevalue + totalflat) * totalmul);
}
-template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, int32& basevalue, Spell* spell);
-template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, uint32& basevalue, Spell* spell);
-template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, float& basevalue, Spell* spell);
+template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, int32& basevalue, Spell* spell) const;
+template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, uint32& basevalue, Spell* spell) const;
+template TC_GAME_API void Player::ApplySpellMod(uint32 spellId, SpellModOp op, float& basevalue, Spell* spell) const;
void Player::AddSpellMod(SpellModifier* mod, bool apply)
{
@@ -21503,9 +21562,9 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
/// First, manipulate our spellmodifier container
if (apply)
- m_spellMods[mod->op][mod->type].push_back(mod);
+ m_spellMods[mod->op][mod->type].insert(mod);
else
- m_spellMods[mod->op][mod->type].remove(mod);
+ m_spellMods[mod->op][mod->type].erase(mod);
/// Now, send spellmodifier packet
if (!IsLoading())
@@ -21531,16 +21590,16 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
if (mod->type == SPELLMOD_FLAT)
{
modData.ModifierValue = 0.0f;
- for (SpellModList::iterator itr = m_spellMods[mod->op][SPELLMOD_FLAT].begin(); itr != m_spellMods[mod->op][SPELLMOD_FLAT].end(); ++itr)
- if ((*itr)->mask & mask)
- modData.ModifierValue += (*itr)->value;
+ for (SpellModifier* spellMod : m_spellMods[mod->op][SPELLMOD_FLAT])
+ if (spellMod->mask & mask)
+ modData.ModifierValue += spellMod->value;
}
else
{
modData.ModifierValue = 1.0f;
- for (SpellModList::iterator itr = m_spellMods[mod->op][SPELLMOD_PCT].begin(); itr != m_spellMods[mod->op][SPELLMOD_PCT].end(); ++itr)
- if ((*itr)->mask & mask)
- modData.ModifierValue *= 1.0f + CalculatePct(1.0f, (*itr)->value);
+ for (SpellModifier* spellMod : m_spellMods[mod->op][SPELLMOD_PCT])
+ if (spellMod->mask & mask)
+ modData.ModifierValue *= 1.0f + CalculatePct(1.0f, spellMod->value);
}
modData.ClassIndex = eff;
@@ -21551,38 +21610,27 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
SendDirectMessage(packet.Write());
}
-
- /// Finally, delete spellmodifier on remove
- if (!apply)
- {
- // mods bound to aura will be removed in AuraEffect::~AuraEffect
- if (!mod->ownerAura)
- delete mod;
- }
}
// Restore spellmods in case of failed cast
-void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
+void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
{
if (!spell || spell->m_appliedMods.empty())
return;
- std::list<Aura*> aurasQueue;
-
- for (uint8 i=0; i<MAX_SPELLMOD; ++i)
+ std::vector<Aura*> aurasQueue;
+ for (uint8 i = 0; i < MAX_SPELLMOD; ++i)
{
for (uint8 j = 0; j < SPELLMOD_END; ++j)
{
- for (SpellModList::iterator itr = m_spellMods[i][j].begin(); itr != m_spellMods[i][j].end(); ++itr)
+ for (SpellModifier* mod : m_spellMods[i][j])
{
- SpellModifier* mod = *itr;
-
- // Spellmods without aura set cannot be charged
- if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
+ // Spellmods without charged aura set cannot be charged
+ if (!mod->ownerAura->IsUsingCharges())
continue;
// Restore only specific owner aura mods
- if (ownerAuraId && (ownerAuraId != mod->ownerAura->GetSpellInfo()->Id))
+ if (ownerAuraId && mod->spellId != ownerAuraId)
continue;
if (aura && mod->ownerAura != aura)
@@ -21603,88 +21651,34 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
// only see the first of its modifier restored)
aurasQueue.push_back(mod->ownerAura);
- // add mod charges back to mod
- if (mod->charges == -1)
- mod->charges = 1;
- else
- mod->charges++;
-
- // Do not set more spellmods than available
- if (mod->ownerAura->GetCharges() < mod->charges)
- mod->charges = mod->ownerAura->GetCharges();
-
- // Skip this check for now - aura charges may change due to various reason
- /// @todo track these changes correctly
- //ASSERT (mod->ownerAura->GetCharges() <= mod->charges);
+ // add charges back to aura
+ mod->ownerAura->ModCharges(1);
}
}
}
- for (std::list<Aura*>::iterator itr = aurasQueue.begin(); itr != aurasQueue.end(); ++itr)
- {
- Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(*itr);
- if (iterMod != spell->m_appliedMods.end())
- spell->m_appliedMods.erase(iterMod);
- }
+ for (Aura* aura : aurasQueue)
+ spell->m_appliedMods.erase(aura);
}
-void Player::RestoreAllSpellMods(uint32 ownerAuraId, Aura* aura)
+void Player::RestoreAllSpellMods(uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
{
for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
- if (m_currentSpells[i])
- RestoreSpellMods(m_currentSpells[i], ownerAuraId, aura);
+ if (Spell* spell = m_currentSpells[i])
+ RestoreSpellMods(spell, ownerAuraId, aura);
}
-void Player::RemoveSpellMods(Spell* spell)
+void Player::ApplyModToSpell(SpellModifier* mod, Spell* spell)
{
if (!spell)
return;
- if (spell->m_appliedMods.empty())
- return;
-
- for (uint8 i = 0; i < MAX_SPELLMOD; ++i)
- {
- for (uint8 j = 0; j < SPELLMOD_END; ++j)
- {
- for (SpellModList::const_iterator itr = m_spellMods[i][j].begin(); itr != m_spellMods[i][j].end();)
- {
- SpellModifier* mod = *itr;
- ++itr;
-
- // spellmods without aura set cannot be charged
- if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
- continue;
-
- // check if mod affected this spell
- Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(mod->ownerAura);
- if (iterMod == spell->m_appliedMods.end())
- continue;
-
- // remove from list
- spell->m_appliedMods.erase(iterMod);
-
- if (mod->ownerAura->DropCharge(AURA_REMOVE_BY_EXPIRE))
- itr = m_spellMods[i][j].begin();
- }
- }
- }
-}
-
-void Player::DropModCharge(SpellModifier* mod, Spell* spell)
-{
- // don't handle spells with proc_event entry defined
- // this is a temporary workaround, because all spellmods should be handled like that
- if (sSpellMgr->GetSpellProcEvent(mod->spellId))
+ // don't do anything with no charges
+ if (mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges())
return;
- if (spell && mod->ownerAura && mod->charges > 0)
- {
- if (--mod->charges == 0)
- mod->charges = -1;
-
- spell->m_appliedMods.insert(mod->ownerAura);
- }
+ // register inside spell, proc system uses this to drop charges
+ spell->m_appliedMods.insert(mod->ownerAura);
}
void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
@@ -21695,7 +21689,7 @@ void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
if (apply && spell->getState() == SPELL_STATE_FINISHED)
return;
- m_spellModTakingSpell = apply ? spell : NULL;
+ m_spellModTakingSpell = apply ? spell : nullptr;
}
void Player::SendSpellModifiers() const
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 385b2ba6917..c94b5804e45 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -113,7 +113,7 @@ enum SkillFieldOffset
#define PLAYER_EXPLORED_ZONES_SIZE 256
// Note: SPELLMOD_* values is aura types in fact
-enum SpellModType
+enum SpellModType : uint8
{
SPELLMOD_FLAT = 0, // SPELL_AURA_ADD_FLAT_MODIFIER
SPELLMOD_PCT = 1, // SPELL_AURA_ADD_PCT_MODIFIER
@@ -208,10 +208,11 @@ enum SpecResetType
// Spell modifier (used for modify other spells)
struct SpellModifier
{
- SpellModifier(Aura* _ownerAura = nullptr) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), charges(0), value(0), mask(), spellId(0), ownerAura(_ownerAura) { }
- SpellModOp op : 8;
- SpellModType type : 8;
- int16 charges : 16;
+ SpellModifier(Aura* _ownerAura) : op(SPELLMOD_DAMAGE), type(SPELLMOD_FLAT), value(0), mask(), spellId(0), ownerAura(_ownerAura) { }
+
+ SpellModOp op;
+ SpellModType type;
+
int32 value;
flag128 mask;
uint32 spellId;
@@ -237,7 +238,7 @@ struct PlayerCurrency
typedef std::unordered_map<uint32, PlayerSpellState> PlayerTalentMap;
typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
-typedef std::list<SpellModifier*> SpellModList;
+typedef std::unordered_set<SpellModifier*> SpellModContainer;
typedef std::unordered_map<uint32, PlayerCurrency> PlayerCurrenciesMap;
typedef std::unordered_map<uint32 /*instanceId*/, time_t/*releaseTime*/> InstanceTimeMap;
@@ -1639,13 +1640,12 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
PlayerSpellMap & GetSpellMap() { return m_spells; }
void AddSpellMod(SpellModifier* mod, bool apply);
- bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr) const;
+ static bool IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod, Spell* spell = nullptr);
template <class T>
- void ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr);
- void RemoveSpellMods(Spell* spell);
+ void ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell = nullptr) const;
void RestoreSpellMods(Spell* spell, uint32 ownerAuraId = 0, Aura* aura = nullptr);
void RestoreAllSpellMods(uint32 ownerAuraId = 0, Aura* aura = nullptr);
- void DropModCharge(SpellModifier* mod, Spell* spell);
+ static void ApplyModToSpell(SpellModifier* mod, Spell* spell);
void SetSpellModTakingSpell(Spell* spell, bool apply);
void SendSpellModifiers() const;
@@ -2016,9 +2016,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void ApplyArtifactPowers(Item* item, bool apply);
void ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const* artifactPowerRank, bool apply);
- void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx);
+ void CastItemCombatSpell(DamageInfo const& damageInfo);
+ void CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto);
void CastItemUseSpell(Item* item, SpellCastTargets const& targets, ObjectGuid castCount, int32* misc);
- void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto);
void SendEquipmentSetList();
void SetEquipmentSet(EquipmentSetInfo::EquipmentSetData const& newEqSet);
@@ -2526,7 +2526,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
uint32 m_baseHealthRegen;
int32 m_spellPenetrationItemMod;
- SpellModList m_spellMods[MAX_SPELLMOD][SPELLMOD_END];
+ SpellModContainer m_spellMods[MAX_SPELLMOD][SPELLMOD_END];
EnchantDurationList m_enchantDuration;
ItemDurationList m_itemDuration;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 923e4514299..22816e1874e 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -104,17 +104,6 @@ float playerBaseMoveSpeed[MAX_MOVE_TYPE] =
3.14f // MOVE_PITCH_RATE
};
-// Used for prepare can/can`t triggr aura
-static bool InitTriggerAuraData();
-// Define can trigger auras
-static bool isTriggerAura[TOTAL_AURAS];
-// Define can't trigger auras (need for disable second trigger)
-static bool isNonTriggerAura[TOTAL_AURAS];
-// Triggered always, even from triggered spells
-static bool isAlwaysTriggeredAura[TOTAL_AURAS];
-// Prepare lists
-static bool procPrepared = InitTriggerAuraData();
-
DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
: m_attacker(attacker), m_victim(victim), m_damage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_damageType(damageType), m_attackType(attackType),
m_absorb(0), m_resist(0), m_block(0), m_hitMask(0)
@@ -158,15 +147,23 @@ DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo)
case MELEE_HIT_EVADE:
m_hitMask |= PROC_HIT_EVADE;
break;
+ case MELEE_HIT_CRUSHING:
+ case MELEE_HIT_GLANCING:
+ case MELEE_HIT_NORMAL:
+ m_hitMask |= PROC_HIT_NORMAL;
+ break;
+ case MELEE_HIT_CRIT:
+ m_hitMask |= PROC_HIT_CRITICAL;
+ break;
default:
break;
}
}
-DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType)
+DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask)
: m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage),
m_spellInfo(sSpellMgr->GetSpellInfo(spellNonMeleeDamage.SpellID)), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType),
- m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(0)
+ m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(hitMask)
{
if (spellNonMeleeDamage.blocked)
m_hitMask |= PROC_HIT_BLOCK;
@@ -1211,7 +1208,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damageInfo->HitInfo = 0;
damageInfo->procAttacker = PROC_FLAG_NONE;
damageInfo->procVictim = PROC_FLAG_NONE;
- damageInfo->procEx = PROC_EX_NONE;
damageInfo->hitOutCome = MELEE_HIT_EVADE;
if (!victim)
@@ -1242,7 +1238,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damageInfo->HitInfo |= HITINFO_NORMALSWING;
damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
- damageInfo->procEx |= PROC_EX_IMMUNE;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
return;
@@ -1272,27 +1267,23 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
case MELEE_HIT_EVADE:
damageInfo->HitInfo |= HITINFO_MISS | HITINFO_SWINGNOHITSOUND;
damageInfo->TargetState = VICTIMSTATE_EVADES;
- damageInfo->procEx |= PROC_EX_EVADE;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
return;
case MELEE_HIT_MISS:
damageInfo->HitInfo |= HITINFO_MISS;
damageInfo->TargetState = VICTIMSTATE_INTACT;
- damageInfo->procEx |= PROC_EX_MISS;
damageInfo->damage = 0;
damageInfo->cleanDamage = 0;
break;
case MELEE_HIT_NORMAL:
damageInfo->TargetState = VICTIMSTATE_HIT;
- damageInfo->procEx |= PROC_EX_NORMAL_HIT;
break;
case MELEE_HIT_CRIT:
{
damageInfo->HitInfo |= HITINFO_CRITICALHIT;
damageInfo->TargetState = VICTIMSTATE_HIT;
- damageInfo->procEx |= PROC_EX_CRITICAL_HIT;
// Crit bonus calc
damageInfo->damage += damageInfo->damage;
float mod = 0.0f;
@@ -1311,20 +1302,17 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
}
case MELEE_HIT_PARRY:
damageInfo->TargetState = VICTIMSTATE_PARRY;
- damageInfo->procEx |= PROC_EX_PARRY;
damageInfo->cleanDamage += damageInfo->damage;
damageInfo->damage = 0;
break;
case MELEE_HIT_DODGE:
damageInfo->TargetState = VICTIMSTATE_DODGE;
- damageInfo->procEx |= PROC_EX_DODGE;
damageInfo->cleanDamage += damageInfo->damage;
damageInfo->damage = 0;
break;
case MELEE_HIT_BLOCK:
damageInfo->TargetState = VICTIMSTATE_HIT;
damageInfo->HitInfo |= HITINFO_BLOCK;
- damageInfo->procEx |= PROC_EX_BLOCK | PROC_EX_NORMAL_HIT;
// 30% damage blocked, double blocked amount if block is critical
damageInfo->blocked_amount = CalculatePct(damageInfo->damage, damageInfo->target->isBlockCritical() ? damageInfo->target->GetBlockPercent() * 2 : damageInfo->target->GetBlockPercent());
damageInfo->damage -= damageInfo->blocked_amount;
@@ -1334,7 +1322,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
{
damageInfo->HitInfo |= HITINFO_GLANCING;
damageInfo->TargetState = VICTIMSTATE_HIT;
- damageInfo->procEx |= PROC_EX_NORMAL_HIT;
int32 leveldif = int32(victim->getLevel()) - int32(getLevel());
if (leveldif > 3)
leveldif = 3;
@@ -1347,7 +1334,6 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
case MELEE_HIT_CRUSHING:
damageInfo->HitInfo |= HITINFO_CRUSHING;
damageInfo->TargetState = VICTIMSTATE_HIT;
- damageInfo->procEx |= PROC_EX_NORMAL_HIT;
// 150% normal damage
damageInfo->damage += (damageInfo->damage / 2);
break;
@@ -1373,10 +1359,7 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
if (damageInfo->absorb)
- {
damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
- damageInfo->procEx |= PROC_EX_ABSORB;
- }
if (damageInfo->resist)
damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
@@ -1466,7 +1449,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
}
if (GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->CastItemCombatSpell(victim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx);
+ {
+ DamageInfo dmgInfo(*damageInfo);
+ ToPlayer()->CastItemCombatSpell(dmgInfo);
+ }
// Do effect if any damage done to target
if (damageInfo->damage)
@@ -1768,7 +1754,7 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
if (absorbAurEff->GetAmount() >= 0)
{
// Reduce shield amount
- absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
+ absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
// Aura cannot absorb anything more - remove it
if (absorbAurEff->GetAmount() <= 0)
absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
@@ -1826,7 +1812,7 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
// Check if our aura is using amount to count damage
if (absorbAurEff->GetAmount() >= 0)
{
- absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
+ absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
if ((absorbAurEff->GetAmount() <= 0))
absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
}
@@ -1883,7 +1869,8 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
SendSpellNonMeleeDamageLog(&log);
// break 'Fear' and similar auras
- caster->ProcDamageAndSpellFor(true, this, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_NORMAL_HIT, BASE_ATTACK, (*itr)->GetSpellInfo(), splitDamage);
+ DamageInfo damageInfo(caster, this, splitDamage, (*itr)->GetSpellInfo(), schoolMask, DIRECT_DAMAGE, BASE_ATTACK);
+ 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);
}
}
@@ -1891,21 +1878,19 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
*absorb = dmgInfo.GetAbsorb();
}
-void Unit::CalcHealAbsorb(Unit* victim, SpellInfo const* healSpell, uint32 &healAmount, uint32 &absorb)
+void Unit::CalcHealAbsorb(HealInfo& healInfo)
{
- if (!healAmount)
+ if (!healInfo.GetHeal())
return;
- int32 RemainingHeal = healAmount;
-
// Need remove expired auras after
bool existExpired = false;
// absorb without mana cost
- AuraEffectList const& vHealAbsorb = victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_HEAL_ABSORB);
- for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i)
+ AuraEffectList const& vHealAbsorb = healInfo.GetTarget()->GetAuraEffectsByType(SPELL_AURA_SCHOOL_HEAL_ABSORB);
+ for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && healInfo.GetHeal() > 0; ++i)
{
- if (!((*i)->GetMiscValue() & healSpell->SchoolMask))
+ if (!((*i)->GetMiscValue() & healInfo.GetSpellInfo()->SchoolMask))
continue;
// Max Amount can be absorbed by this aura
@@ -1920,13 +1905,12 @@ void Unit::CalcHealAbsorb(Unit* victim, SpellInfo const* healSpell, uint32 &heal
// currentAbsorb - damage can be absorbed by shield
// If need absorb less damage
- if (RemainingHeal < currentAbsorb)
- currentAbsorb = RemainingHeal;
+ currentAbsorb = std::min<int32>(healInfo.GetHeal(), currentAbsorb);
- RemainingHeal -= currentAbsorb;
+ healInfo.AbsorbHeal(currentAbsorb);
// Reduce shield amount
- (*i)->SetAmount((*i)->GetAmount() - currentAbsorb);
+ (*i)->ChangeAmount((*i)->GetAmount() - currentAbsorb);
// Need remove it later
if ((*i)->GetAmount() <= 0)
existExpired = true;
@@ -1941,19 +1925,16 @@ void Unit::CalcHealAbsorb(Unit* victim, SpellInfo const* healSpell, uint32 &heal
++i;
if (auraEff->GetAmount() <= 0)
{
- uint32 removedAuras = victim->m_removedAurasCount;
+ uint32 removedAuras = healInfo.GetTarget()->m_removedAurasCount;
auraEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
- if (removedAuras+1 < victim->m_removedAurasCount)
+ if (removedAuras + 1 < healInfo.GetTarget()->m_removedAurasCount)
i = vHealAbsorb.begin();
}
}
}
-
- absorb = RemainingHeal > 0 ? (healAmount - RemainingHeal) : healAmount;
- healAmount = RemainingHeal;
}
-void Unit::AttackerStateUpdate (Unit* victim, WeaponAttackType attType, bool extra)
+void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
{
if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
return;
@@ -1987,8 +1968,7 @@ void Unit::AttackerStateUpdate (Unit* victim, WeaponAttackType attType, bool ext
DealDamageMods(victim, damageInfo.damage, &damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
- //TriggerAurasProcOnEvent(damageInfo);
- ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
+ TriggerAurasProcOnEvent(damageInfo);
DealMeleeDamage(&damageInfo, true);
@@ -2035,7 +2015,6 @@ void Unit::FakeAttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BA
damageInfo.procAttacker = PROC_FLAG_NONE;
damageInfo.procVictim = PROC_FLAG_NONE;
- damageInfo.procEx = PROC_EX_NONE;
damageInfo.hitOutCome = MELEE_HIT_NORMAL;
SendAttackStateUpdate(&damageInfo);
@@ -2585,12 +2564,9 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spellInfo, boo
for (Unit::AuraEffectList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
if ((*i)->GetMiscValue() & spellInfo->GetSchoolMask())
reflectchance += (*i)->GetAmount();
+
if (reflectchance > 0 && roll_chance_i(reflectchance))
- {
- // Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
- ProcDamageAndSpell(victim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_EX_REFLECT, 1, BASE_ATTACK, spellInfo);
return SPELL_MISS_REFLECT;
- }
}
switch (spellInfo->DmgClass)
@@ -5067,15 +5043,16 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const* log)
SendCombatLogMessage(&packet);
}
-void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellInfo const* procSpell, SpellInfo const* procAura)
+void Unit::ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
{
- // Not much to do if no flags are set.
- if (procAttacker)
- ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpell, amount, procAura);
- // Now go on with a victim's events'n'auras
- // Not much to do if no flags are set or there is no victim
- if (victim && victim->IsAlive() && procVictim)
- victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount, procAura);
+ WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
+ if (typeMaskActor && CanProc())
+ ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
+
+ if (typeMaskActionTarget && actionTarget && actionTarget->CanProc())
+ actionTarget->ProcSkillsAndReactives(true, this, typeMaskActionTarget, hitMask, attType);
+
+ TriggerAurasProcOnEvent(nullptr, nullptr, actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
}
void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* info)
@@ -5180,137 +5157,6 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
SendAttackStateUpdate(&dmgInfo);
}
-//victim may be NULL
-bool Unit::HandleDummyAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/)
-{
- SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
-
- Item* castItem = !triggeredByAura->GetBase()->GetCastItemGUID().IsEmpty() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- Unit* target = victim;
-
- uint32 triggered_spell_id = triggeredByAura->GetSpellEffectInfo()->TriggerSpell;
-
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!triggerEntry)
- {
- TC_LOG_ERROR("entities.unit", "Unit::HandleDummyAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
-
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- return true;
-}
-
-bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 procFlag, uint32 /*procEx*/)
-{
- // Get triggered aura spell info
- SpellInfo const* auraSpellInfo = triggeredByAura->GetSpellInfo();
-
- // Basepoints of trigger aura
- int32 triggerAmount = triggeredByAura->GetAmount();
-
- // Set trigger spell id, target, custom basepoints
- uint32 trigger_spell_id = triggeredByAura->GetSpellEffectInfo()->TriggerSpell;
-
- Unit* target = NULL;
- int32 basepoints0 = 0;
-
- if (triggeredByAura->GetAuraType() == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE)
- basepoints0 = triggerAmount;
-
- Item* castItem = !triggeredByAura->GetBase()->GetCastItemGUID().IsEmpty() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- // All ok. Check current trigger spell
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(trigger_spell_id);
- if (triggerEntry == NULL)
- {
- // Don't cast unknown spell
- TC_LOG_ERROR("entities.unit.handleproctriggerspell", "Unit::HandleProcTriggerSpell: Spell %u (effIndex: %u) has unknown TriggerSpell %u. Unhandled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex(), trigger_spell_id);
- return false;
- }
-
- // not allow proc extra attack spell at extra attack
- if (m_extraAttacks && triggerEntry->HasEffect(GetMap()->GetDifficultyID(), SPELL_EFFECT_ADD_EXTRA_ATTACKS))
- return false;
-
- // Custom basepoints/target for exist spell
- // dummy basepoints or other customs
- switch (trigger_spell_id)
- {
- // Maelstrom Weapon
- case 53817:
- {
- // Item - Shaman T10 Enhancement 4P Bonus
- if (AuraEffect const* aurEff = GetAuraEffect(70832, 0))
- if (Aura const* maelstrom = GetAura(53817))
- if ((maelstrom->GetStackAmount() == maelstrom->GetSpellInfo()->StackAmount) && roll_chance_i(aurEff->GetAmount()))
- CastSpell(this, 70831, true, castItem, triggeredByAura);
- break;
- }
- }
-
- // extra attack should hit same target
- if (triggerEntry->HasEffect(GetMap()->GetDifficultyID(), SPELL_EFFECT_ADD_EXTRA_ATTACKS))
- target = victim;
-
- // try detect target manually if not set
- if (target == NULL)
- target = !(procFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)) && triggerEntry->IsPositive() ? this : victim;
-
- if (basepoints0)
- CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
-
- return true;
-}
-
-bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/)
-{
- int32 scriptId = triggeredByAura->GetMiscValue();
-
- if (!victim || !victim->IsAlive())
- return false;
-
- Item* castItem = !triggeredByAura->GetBase()->GetCastItemGUID().IsEmpty() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
-
- switch (scriptId)
- {
- case 4537: // Dreamwalker Raiment 6 pieces bonus
- triggered_spell_id = 28750; // Blessing of the Claw
- break;
- default:
- break;
- }
-
- // not processed
- if (!triggered_spell_id)
- return false;
-
- // standard non-dummy case
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- if (!triggerEntry)
- {
- TC_LOG_ERROR("entities.unit", "Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u", triggered_spell_id, scriptId);
- return false;
- }
-
- CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura);
- return true;
-}
-
void Unit::setPowerType(Powers new_powertype)
{
if (getPowerType() == new_powertype)
@@ -5847,9 +5693,9 @@ uint32 Unit::BuildAuraStateUpdateForTarget(Unit* target) const
{
uint32 auraStates = GetUInt32Value(UNIT_FIELD_AURASTATE) &~(PER_CASTER_AURA_STATE_MASK);
for (AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
- if ((1<<(itr->first-1)) & PER_CASTER_AURA_STATE_MASK)
+ if ((1 << (itr->first - 1)) & PER_CASTER_AURA_STATE_MASK)
if (itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
- auraStates |= (1<<(itr->first-1));
+ auraStates |= (1 << (itr->first - 1));
return auraStates;
}
@@ -5861,13 +5707,14 @@ bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit co
if (spellProto)
{
AuraEffectList const& stateAuras = Caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
- for (AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j)
- if ((*j)->IsAffectingSpell(spellProto))
+ for (AuraEffect const* aurEff : stateAuras)
+ if (aurEff->IsAffectingSpell(spellProto))
return true;
}
+
// Check per caster aura state
// If aura with aurastate by caster not found return false
- if ((1<<(flag-1)) & PER_CASTER_AURA_STATE_MASK)
+ if ((1 << (flag - 1)) & PER_CASTER_AURA_STATE_MASK)
{
AuraStateAurasMapBounds range = m_auraStateAuras.equal_range(flag);
for (AuraStateAurasMap::const_iterator itr = range.first; itr != range.second; ++itr)
@@ -5877,7 +5724,7 @@ bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit co
}
}
- return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
+ return HasFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1));
}
void Unit::SetOwnerGUID(ObjectGuid owner)
@@ -6248,9 +6095,11 @@ void Unit::SetCharm(Unit* charm, bool apply)
}
}
-int32 Unit::DealHeal(Unit* victim, uint32 addhealth)
+void Unit::DealHeal(HealInfo& healInfo)
{
int32 gain = 0;
+ Unit* victim = healInfo.GetTarget();
+ uint32 addhealth = healInfo.GetHeal();
if (victim->IsAIEnabled)
victim->GetAI()->HealReceived(this, addhealth);
@@ -6287,7 +6136,8 @@ int32 Unit::DealHeal(Unit* victim, uint32 addhealth)
player->UpdateCriteria(CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth);
}
- return gain;
+ if (gain)
+ healInfo.SetEffectiveHeal(gain > 0 ? static_cast<uint32>(gain) : 0UL);
}
bool Unit::IsMagnet() const
@@ -6503,22 +6353,22 @@ void Unit::UnsummonAllTotems()
}
}
-void Unit::SendHealSpellLog(Unit* victim, uint32 spellID, uint32 health, uint32 overHeal, uint32 absorbed, bool crit)
+void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
{
WorldPackets::CombatLog::SpellHealLog spellHealLog;
- TC_LOG_DEBUG("spells", "HealSpellLog -- SpellId: %u Caster: %s Target: %s (Health: %u OverHeal: %u Absorbed: %u Crit: %d)", spellID, GetGUID().ToString().c_str(), victim->GetGUID().ToString().c_str(),
- health, overHeal, absorbed, crit);
+ TC_LOG_DEBUG("spells", "HealSpellLog -- SpellId: %u Caster: %s Target: %s (Health: %u OverHeal: %u Absorbed: %u Crit: %d)", healInfo.GetSpellInfo()->Id, GetGUID().ToString().c_str(), healInfo.GetTarget()->GetGUID().ToString().c_str(),
+ healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), critical);
- spellHealLog.TargetGUID = victim->GetGUID();
+ spellHealLog.TargetGUID = healInfo.GetTarget()->GetGUID();
spellHealLog.CasterGUID = GetGUID();
- spellHealLog.SpellID = spellID;
- spellHealLog.Health = health;
- spellHealLog.OverHeal = overHeal;
- spellHealLog.Absorbed = absorbed;
+ spellHealLog.SpellID = healInfo.GetSpellInfo()->Id;
+ spellHealLog.Health = healInfo.GetHeal();
+ spellHealLog.OverHeal = int32(healInfo.GetHeal()) - healInfo.GetEffectiveHeal();
+ spellHealLog.Absorbed = healInfo.GetAbsorb();
- spellHealLog.Crit = crit;
+ spellHealLog.Crit = critical;
/// @todo: 6.x Has to be implemented
/*
@@ -6538,19 +6388,18 @@ void Unit::SendHealSpellLog(Unit* victim, uint32 spellID, uint32 health, uint32
SpellParsers.ReadSpellCastLogData(packet);
*/
- spellHealLog.LogData.Initialize(victim);
+ spellHealLog.LogData.Initialize(healInfo.GetTarget());
SendCombatLogMessage(&spellHealLog);
}
-int32 Unit::HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical)
+int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
{
- uint32 absorb = 0;
// calculate heal absorb and reduce healing
- CalcHealAbsorb(victim, spellInfo, addHealth, absorb);
+ CalcHealAbsorb(healInfo);
- int32 gain = DealHeal(victim, addHealth);
- SendHealSpellLog(victim, spellInfo->Id, addHealth, uint32(addHealth - gain), absorb, critical);
- return gain;
+ DealHeal(healInfo);
+ SendHealSpellLog(healInfo, critical);
+ return healInfo.GetEffectiveHeal();
}
void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, int32 overEnergize, Powers powertype)
@@ -6636,7 +6485,12 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
float tmpDamage = (int32(pdamage) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellDamagePctDone(victim, spellProto, damagetype));
// apply spellmod to Done damage (flat and pct)
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
+ {
+ if (damagetype == DOT)
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DOT, tmpDamage);
+ else
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
+ }
return uint32(std::max(tmpDamage, 0.0f));
}
@@ -7137,7 +6991,12 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
float heal = float(int32(healamount) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellHealingPctDone(victim, spellProto));
// apply spellmod to Done amount
if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
+ {
+ if (damagetype == DOT)
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DOT, heal);
+ else
+ modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, heal);
+ }
return uint32(std::max(heal, 0.0f));
}
@@ -7734,7 +7593,7 @@ float Unit::GetWeaponProcChance() const
return 0;
}
-float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellInfo* spellProto) const
+float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spellProto) const
{
// proc per minute chance calculation
if (PPM <= 0)
@@ -8968,19 +8827,19 @@ float Unit::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, value);
switch (effect_index)
{
- case 0:
+ case EFFECT_0:
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT1, value);
break;
- case 1:
+ case EFFECT_1:
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT2, value);
break;
- case 2:
+ case EFFECT_2:
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT3, value);
break;
- case 3:
+ case EFFECT_3:
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT4, value);
break;
- case 4:
+ case EFFECT_4:
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_EFFECT5, value);
break;
}
@@ -10203,145 +10062,83 @@ bool Unit::isFrozen() const
return HasAuraState(AURA_STATE_FROZEN);
}
-struct ProcTriggeredData
+uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition)
{
- ProcTriggeredData(Aura* _aura)
- : aura(_aura)
- {
- effMask = 0;
- spellProcEvent = NULL;
- }
- SpellProcEventEntry const* spellProcEvent;
- Aura* aura;
- uint32 effMask;
-};
-
-typedef std::list< ProcTriggeredData > ProcTriggeredList;
-
-// List of auras that CAN be trigger but may not exist in spell_proc_event
-// in most case need for drop charges
-// in some types of aura need do additional check
-// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic
-bool InitTriggerAuraData()
-{
- for (uint16 i = 0; i < TOTAL_AURAS; ++i)
- {
- isTriggerAura[i] = false;
- isNonTriggerAura[i] = false;
- isAlwaysTriggeredAura[i] = false;
- }
- isTriggerAura[SPELL_AURA_PROC_ON_POWER_AMOUNT] = true;
- isTriggerAura[SPELL_AURA_PROC_ON_POWER_AMOUNT_2] = true;
- isTriggerAura[SPELL_AURA_DUMMY] = true;
- isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true;
- isTriggerAura[SPELL_AURA_MOD_THREAT] = true;
- isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
- isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
- isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
- isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
- isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
- isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
- isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
- isTriggerAura[SPELL_AURA_TRANSFORM] = true;
- isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
- isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
- isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
- isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
- isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
- isTriggerAura[SPELL_AURA_SCHOOL_ABSORB] = true; // Savage Defense untested
- isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
- isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
- isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
- isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true;
- isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
- isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true;
- isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
- isTriggerAura[SPELL_AURA_MOD_POWER_REGEN_PERCENT] = true;
- isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
- isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
- isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true;
- isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true;
- isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
- isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE_3] = true;
- isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
- isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true;
- isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true;
- isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
- isTriggerAura[SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER] = true;
- isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
- isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
- isTriggerAura[SPELL_AURA_MOD_ROOT_2] = true;
-
- isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN] = true;
- isNonTriggerAura[SPELL_AURA_REDUCE_PUSHBACK] = true;
-
- isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
- isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
- isAlwaysTriggeredAura[SPELL_AURA_SPELL_MAGNET] = true;
- isAlwaysTriggeredAura[SPELL_AURA_SCHOOL_ABSORB] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
- isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT_2] = true;
-
- return true;
-}
-
-uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition)
-{
- uint32 procEx = PROC_EX_NONE;
+ uint32 hitMask = PROC_HIT_NONE;
// Check victim state
if (missCondition != SPELL_MISS_NONE)
+ {
switch (missCondition)
{
- case SPELL_MISS_MISS: procEx|=PROC_EX_MISS; break;
- case SPELL_MISS_RESIST: procEx|=PROC_EX_RESIST; break;
- case SPELL_MISS_DODGE: procEx|=PROC_EX_DODGE; break;
- case SPELL_MISS_PARRY: procEx|=PROC_EX_PARRY; break;
- case SPELL_MISS_BLOCK: procEx|=PROC_EX_BLOCK; break;
- case SPELL_MISS_EVADE: procEx|=PROC_EX_EVADE; break;
- case SPELL_MISS_IMMUNE: procEx|=PROC_EX_IMMUNE; break;
- case SPELL_MISS_IMMUNE2: procEx|=PROC_EX_IMMUNE; break;
- case SPELL_MISS_DEFLECT: procEx|=PROC_EX_DEFLECT;break;
- case SPELL_MISS_ABSORB: procEx|=PROC_EX_ABSORB; break;
- case SPELL_MISS_REFLECT: procEx|=PROC_EX_REFLECT;break;
+ case SPELL_MISS_MISS:
+ hitMask |= PROC_HIT_MISS;
+ break;
+ case SPELL_MISS_DODGE:
+ hitMask |= PROC_HIT_DODGE;
+ break;
+ case SPELL_MISS_PARRY:
+ hitMask |= PROC_HIT_PARRY;
+ break;
+ case SPELL_MISS_BLOCK:
+ hitMask |= PROC_HIT_BLOCK;
+ break;
+ case SPELL_MISS_EVADE:
+ hitMask |= PROC_HIT_EVADE;
+ break;
+ case SPELL_MISS_IMMUNE:
+ hitMask |= PROC_HIT_IMMUNE;
+ break;
+ case SPELL_MISS_IMMUNE2:
+ hitMask |= PROC_HIT_IMMUNE;
+ break;
+ case SPELL_MISS_DEFLECT:
+ hitMask |= PROC_HIT_DEFLECT;
+ break;
+ case SPELL_MISS_ABSORB:
+ hitMask |= PROC_HIT_ABSORB;
+ break;
+ case SPELL_MISS_REFLECT:
+ hitMask |= PROC_HIT_REFLECT;
+ break;
default:
break;
}
+ }
else
{
// On block
if (damageInfo->blocked)
- procEx|=PROC_EX_BLOCK;
+ hitMask |= PROC_HIT_BLOCK;
// On absorb
if (damageInfo->absorb)
- procEx|=PROC_EX_ABSORB;
+ hitMask |= PROC_HIT_ABSORB;
// On crit
if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
- procEx|=PROC_EX_CRITICAL_HIT;
+ hitMask |= PROC_HIT_CRITICAL;
else
- procEx|=PROC_EX_NORMAL_HIT;
+ hitMask |= PROC_HIT_NORMAL;
}
- return procEx;
+
+ return hitMask;
}
-void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura)
+void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType /*attType*/)
{
// Player is loaded now - do not allow passive spell casts to proc
if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
return;
+
// For melee/ranged based attack need update skills and set some Aura states if victim present
- if (procFlag & MELEE_BASED_TRIGGER_MASK && target)
+ if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget)
{
// If exist crit/parry/dodge/block need update aura state (for victim and attacker)
- if (procExtra & (PROC_EX_CRITICAL_HIT|PROC_EX_PARRY|PROC_EX_DODGE|PROC_EX_BLOCK))
+ if (hitMask & (PROC_HIT_CRITICAL | PROC_HIT_PARRY | PROC_HIT_DODGE | PROC_HIT_BLOCK))
{
// for victim
if (isVictim)
{
// if victim and dodge attack
- if (procExtra & PROC_EX_DODGE)
+ if (hitMask & PROC_HIT_DODGE)
{
// Update AURA_STATE on dodge
if (getClass() != CLASS_ROGUE) // skip Rogue Riposte
@@ -10351,7 +10148,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
}
}
// if victim and parry attack
- if (procExtra & PROC_EX_PARRY)
+ if (hitMask & PROC_HIT_PARRY)
{
// For Hunters only Counterattack (skip Mongoose bite)
if (getClass() == CLASS_HUNTER)
@@ -10366,7 +10163,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
}
}
// if and victim block attack
- if (procExtra & PROC_EX_BLOCK)
+ if (hitMask & PROC_HIT_BLOCK)
{
ModifyAuraState(AURA_STATE_DEFENSE, true);
StartReactiveTimer(REACTIVE_DEFENSE);
@@ -10375,7 +10172,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
else // For attacker
{
// Overpower on victim dodge
- if (procExtra & PROC_EX_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
+ if ((hitMask & PROC_HIT_DODGE) && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
{
ToPlayer()->AddComboPoints(1);
StartReactiveTimer(REACTIVE_OVERPOWER);
@@ -10383,382 +10180,34 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
}
}
}
-
- Unit* actor = isVictim ? target : this;
- Unit* actionTarget = !isVictim ? target : this;
-
- DamageInfo damageInfo = DamageInfo(actor, actionTarget, damage, procSpell, procSpell ? SpellSchoolMask(procSpell->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL, SPELL_DIRECT_DAMAGE, attType);
- HealInfo healInfo = HealInfo(actor, actionTarget, damage, procSpell, procSpell ? SpellSchoolMask(procSpell->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL);
- ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, nullptr, &damageInfo, &healInfo);
-
- std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
- ProcTriggeredList procTriggered;
- // Fill procTriggered list
- for (AuraApplicationMap::const_iterator itr = GetAppliedAuras().begin(); itr!= GetAppliedAuras().end(); ++itr)
- {
- // Do not allow auras to proc from effect triggered by itself
- if (procAura && procAura->Id == itr->first)
- continue;
-
- if (itr->second->GetBase()->IsProcOnCooldown(now))
- continue;
-
- ProcTriggeredData triggerData(itr->second->GetBase());
- // Defensive procs are active on absorbs (so absorption effects are not a hindrance)
- bool active = damage || (procExtra & PROC_EX_BLOCK && isVictim);
- if (isVictim)
- procExtra &= ~PROC_EX_INTERNAL_REQ_FAMILY;
-
- SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
-
- // only auras that has triggered spell should proc from fully absorbed damage
- if (procExtra & PROC_EX_ABSORB && isVictim && damage)
- {
- for (SpellEffectInfo const* effect : itr->second->GetBase()->GetSpellEffectInfos())
- {
- if (effect && effect->TriggerSpell)
- {
- active = true;
- break;
- }
- }
- }
-
- if (!IsTriggeredAtSpellProcEvent(target, triggerData.aura, procSpell, procFlag, procExtra, attType, isVictim, active, triggerData.spellProcEvent))
- continue;
-
- // do checks using conditions table
- if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL_PROC, spellProto->Id, eventInfo.GetActor(), eventInfo.GetActionTarget()))
- continue;
-
- // AuraScript Hook
- if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo))
- continue;
-
- bool procSuccess = RollProcResult(target, triggerData.aura, attType, isVictim, triggerData.spellProcEvent);
- triggerData.aura->SetLastProcAttemptTime(now);
- if (!procSuccess)
- continue;
-
- bool triggeredCanProcAura = true;
- // Additional checks for triggered spells (ignore trap casts)
- if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION))
- {
- if (!spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
- triggeredCanProcAura = false;
- }
-
- for (AuraEffect const* aurEff : itr->second->GetBase()->GetAuraEffects())
- {
- if (aurEff)
- {
- // Skip this auras
- if (isNonTriggerAura[aurEff->GetAuraType()])
- continue;
- // If not trigger by default and spellProcEvent == NULL - skip
- if (!isTriggerAura[aurEff->GetAuraType()] && triggerData.spellProcEvent == NULL)
- continue;
- // Some spells must always trigger
- if (triggeredCanProcAura || isAlwaysTriggeredAura[aurEff->GetAuraType()])
- triggerData.effMask |= 1 << aurEff->GetEffIndex();
- }
- }
- if (triggerData.effMask)
- procTriggered.push_front(triggerData);
- }
-
- // Nothing found
- if (procTriggered.empty())
- return;
-
- // Note: must SetCantProc(false) before return
- if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC))
- SetCantProc(true);
-
- // Handle effects proceed this time
- for (ProcTriggeredList::const_iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
- {
- // look for aura in auras list, it may be removed while proc event processing
- if (i->aura->IsRemoved())
- continue;
-
- bool useCharges = i->aura->IsUsingCharges();
- // no more charges to use, prevent proc
- if (useCharges && !i->aura->GetCharges())
- continue;
-
- bool takeCharges = false;
- SpellInfo const* spellInfo = i->aura->GetSpellInfo();
- uint32 Id = i->aura->GetId();
-
- AuraApplication* aurApp = i->aura->GetApplicationOfTarget(GetGUID());
- ASSERT(aurApp);
-
- bool prepare = i->aura->CallScriptPrepareProcHandlers(aurApp, eventInfo);
-
- Milliseconds cooldown = Milliseconds::zero();
- if (prepare)
- {
- cooldown = Milliseconds(spellInfo->ProcCooldown);
- if (i->spellProcEvent && i->spellProcEvent->cooldown)
- cooldown = Seconds(i->spellProcEvent->cooldown);
- }
-
- i->aura->SetLastProcSuccessTime(now);
-
- // Note: must SetCantProc(false) before return
- if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
- SetCantProc(true);
-
- bool handled = i->aura->CallScriptProcHandlers(aurApp, eventInfo);
-
- // "handled" is needed as long as proc can be handled in multiple places
- if (!handled)
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), Id);
- takeCharges = true;
- }
-
- if (!handled)
- {
- for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
- {
- if (!(i->effMask & (1 << effIndex)))
- continue;
-
- AuraEffect* triggeredByAura = i->aura->GetEffect(effIndex);
- ASSERT(triggeredByAura);
-
- bool prevented = i->aura->CallScriptEffectProcHandlers(triggeredByAura, aurApp, eventInfo);
- if (prevented)
- {
- takeCharges = true;
- continue;
- }
-
- switch (triggeredByAura->GetAuraType())
- {
- case SPELL_AURA_PROC_TRIGGER_SPELL:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)",
- spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
- // Don`t drop charge or add cooldown for not started trigger
- if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpell, procFlag, procExtra))
- takeCharges = true;
- break;
- }
- case SPELL_AURA_PROC_TRIGGER_DAMAGE:
- {
- // target has to be valid
- if (!eventInfo.GetProcTarget())
- break;
-
- triggeredByAura->HandleProcTriggerDamageAuraProc(aurApp, eventInfo); // this function is part of the new proc system
- takeCharges = true;
- break;
- }
- case SPELL_AURA_MANA_SHIELD:
- case SPELL_AURA_DUMMY:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)",
- spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
- if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra))
- takeCharges = true;
- break;
- }
- case SPELL_AURA_PROC_ON_POWER_AMOUNT:
- case SPELL_AURA_PROC_ON_POWER_AMOUNT_2:
- {
- triggeredByAura->HandleProcTriggerSpellOnPowerAmountAuraProc(aurApp, eventInfo);
- takeCharges = true;
- break;
- }
- case SPELL_AURA_OBS_MOD_POWER:
- case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
- case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
- case SPELL_AURA_MOD_POWER_REGEN_PERCENT:
- case SPELL_AURA_MOD_MELEE_HASTE:
- case SPELL_AURA_MOD_MELEE_HASTE_3:
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)",
- spellInfo->Id, isVictim ? "a victim's" : "an attacker's", triggeredByAura->GetId());
- takeCharges = true;
- break;
- case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)",
- spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
- if (HandleOverrideClassScriptAuraProc(target, damage, triggeredByAura, procSpell))
- takeCharges = true;
- break;
- }
- case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
- (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
-
- HandleAuraRaidProcFromChargeWithValue(triggeredByAura);
- takeCharges = true;
- break;
- }
- case SPELL_AURA_RAID_PROC_FROM_CHARGE:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
- (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
-
- HandleAuraRaidProcFromCharge(triggeredByAura);
- takeCharges = true;
- break;
- }
- case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
- {
- TC_LOG_DEBUG("spells", "ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)",
- spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
-
- if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpell, procFlag, procExtra))
- takeCharges = true;
- break;
- }
- case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
- // Skip melee hits or instant cast spells
- if (procSpell && procSpell->CalcCastTime(getLevel()) > 0)
- takeCharges = true;
- break;
- case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
- // Skip Melee hits and spells ws wrong school
- if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check
- takeCharges = true;
- break;
- case SPELL_AURA_SPELL_MAGNET:
- // Skip Melee hits and targets with magnet aura
- if (procSpell && (triggeredByAura->GetBase()->GetUnitOwner()->ToUnit() == ToUnit())) // Magnet
- takeCharges = true;
- break;
- case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
- case SPELL_AURA_MOD_POWER_COST_SCHOOL:
- // Skip melee hits and spells ws wrong school or zero cost
- if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check
- {
- std::vector<SpellPowerCost> costs = procSpell->CalcPowerCost(this, procSpell->GetSchoolMask());
- auto m = std::find_if(costs.begin(), costs.end(), [](SpellPowerCost const& cost) { return cost.Amount > 0; });
- if (m != costs.end())
- takeCharges = true;
- }
- break;
- case SPELL_AURA_MECHANIC_IMMUNITY:
- // Compare mechanic
- if (procSpell && procSpell->Mechanic == uint32(triggeredByAura->GetMiscValue()))
- takeCharges = true;
- break;
- case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
- // Compare mechanic
- if (procSpell && procSpell->Mechanic == uint32(triggeredByAura->GetMiscValue()))
- takeCharges = true;
- break;
- case SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER:
- // Compare casters
- if (triggeredByAura->GetCasterGUID() == target->GetGUID())
- takeCharges = true;
- break;
- // CC Auras which use their amount amount to drop
- // Are there any more auras which need this?
- case SPELL_AURA_MOD_CONFUSE:
- case SPELL_AURA_MOD_FEAR:
- case SPELL_AURA_MOD_STUN:
- case SPELL_AURA_MOD_ROOT:
- case SPELL_AURA_TRANSFORM:
- case SPELL_AURA_MOD_ROOT_2:
- {
- // chargeable mods are breaking on hit
- if (useCharges)
- takeCharges = true;
- else
- {
- // Spell own direct damage at apply wont break the CC
- if (procSpell && (procSpell->Id == triggeredByAura->GetId()))
- {
- Aura* aura = triggeredByAura->GetBase();
- // called from spellcast, should not have ticked yet
- if (aura->GetDuration() == aura->GetMaxDuration())
- break;
- }
- int32 damageLeft = triggeredByAura->GetAmount();
- // No damage left
- if (damageLeft < int32(damage))
- i->aura->Remove();
- else
- triggeredByAura->SetAmount(damageLeft - damage);
- }
- break;
- }
- //case SPELL_AURA_ADD_FLAT_MODIFIER:
- //case SPELL_AURA_ADD_PCT_MODIFIER:
- // HandleSpellModAuraProc
- //break;
- default:
- // nothing do, just charges counter
- takeCharges = true;
- break;
- } // switch (triggeredByAura->GetAuraType())
- i->aura->CallScriptAfterEffectProcHandlers(triggeredByAura, aurApp, eventInfo);
- } // for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
- } // if (!handled)
-
- if (prepare && takeCharges && cooldown != Milliseconds::zero())
- i->aura->AddProcCooldown(now + cooldown);
-
- // Remove charge (aura can be removed by triggers)
- if (prepare && useCharges && takeCharges)
- {
- // Set charge drop delay (only for missiles)
- if ((procExtra & PROC_EX_REFLECT) && target && procSpell && procSpell->Speed > 0.0f)
- {
- // Set up missile speed based delay (from Spell.cpp: Spell::AddUnitTarget()::L2237)
- uint32 delay = uint32(std::floor(std::max<float>(target->GetDistance(this), 5.0f) / procSpell->Speed * 1000.0f));
- // Schedule charge drop
- i->aura->DropChargeDelayed(delay);
- }
- else
- i->aura->DropCharge();
- }
-
- i->aura->CallScriptAfterProcHandlers(aurApp, eventInfo);
-
- if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
- SetCantProc(false);
- }
-
- // Cleanup proc requirements
- if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC))
- SetCantProc(false);
}
-void Unit::GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTriggeringProc, std::list<AuraApplication*>* procAuras, ProcEventInfo eventInfo)
+void Unit::GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo)
{
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
// use provided list of auras which can proc
if (procAuras)
{
- for (std::list<AuraApplication*>::iterator itr = procAuras->begin(); itr!= procAuras->end(); ++itr)
+ for (AuraApplication* aurApp : *procAuras)
{
- ASSERT((*itr)->GetTarget() == this);
- if (!(*itr)->GetRemoveMode())
- if ((*itr)->GetBase()->IsProcTriggeredOnEvent(*itr, eventInfo, now))
- {
- (*itr)->GetBase()->PrepareProcToTrigger(*itr, eventInfo, now);
- aurasTriggeringProc.push_back(*itr);
- }
+ ASSERT(aurApp->GetTarget() == this);
+ if (uint32 procEffectMask = aurApp->GetBase()->IsProcTriggeredOnEvent(aurApp, eventInfo, now))
+ {
+ aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
+ aurasTriggeringProc.emplace_back(std::make_pair(procEffectMask, aurApp));
+ }
}
}
// or generate one on our own
else
{
- for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr!= GetAppliedAuras().end(); ++itr)
+ for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
{
- if (itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo, now))
+ if (uint32 procEffectMask = itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo, now))
{
itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now);
- aurasTriggeringProc.push_back(itr->second);
+ aurasTriggeringProc.emplace_back(std::make_pair(procEffectMask, itr->second));
}
}
}
@@ -10767,34 +10216,48 @@ void Unit::GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTrigge
void Unit::TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo)
{
DamageInfo dmgInfo = DamageInfo(damageInfo);
- TriggerAurasProcOnEvent(NULL, NULL, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, 0, 0, damageInfo.procEx, NULL, &dmgInfo, NULL);
+ TriggerAurasProcOnEvent(nullptr, nullptr, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
}
-void Unit::TriggerAurasProcOnEvent(std::list<AuraApplication*>* myProcAuras, std::list<AuraApplication*>* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
+void Unit::TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplicationList* targetProcAuras, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
{
// prepare data for self trigger
- ProcEventInfo myProcEventInfo = ProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
- std::list<AuraApplication*> myAurasTriggeringProc;
- GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo);
+ ProcEventInfo myProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
+ AuraApplicationProcContainer myAurasTriggeringProc;
+ if (typeMaskActor && CanProc())
+ GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo);
// prepare data for target trigger
- ProcEventInfo targetProcEventInfo = ProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
- std::list<AuraApplication*> targetAurasTriggeringProc;
- if (typeMaskActionTarget)
- GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo);
+ ProcEventInfo targetProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
+ AuraApplicationProcContainer targetAurasTriggeringProc;
+ if (typeMaskActionTarget && actionTarget && actionTarget->CanProc())
+ actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo);
TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
- if (typeMaskActionTarget)
- TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
+ if (typeMaskActionTarget && actionTarget)
+ actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
}
-void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list<AuraApplication*>& aurasTriggeringProc)
+void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& aurasTriggeringProc)
{
- for (std::list<AuraApplication*>::iterator itr = aurasTriggeringProc.begin(); itr != aurasTriggeringProc.end(); ++itr)
+ for (auto const& aurAppProc : aurasTriggeringProc)
{
- if (!(*itr)->GetRemoveMode())
- (*itr)->GetBase()->TriggerProcOnEvent(*itr, eventInfo);
+ AuraApplication* aurApp;
+ uint32 procEffectMask;
+ std::tie(procEffectMask, aurApp) = aurAppProc;
+
+ if (aurApp->GetRemoveMode())
+ continue;
+
+ SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
+ if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
+ SetCantProc(true);
+
+ aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo);
+
+ if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
+ SetCantProc(false);
}
}
@@ -11400,207 +10863,6 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
return true;
}
-bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent)
-{
- SpellInfo const* spellInfo = aura->GetSpellInfo();
-
- // let the aura be handled by new proc system if it has new entry
- if (sSpellMgr->GetSpellProcEntry(spellInfo->Id))
- return false;
-
- // Get proc Event Entry
- spellProcEvent = sSpellMgr->GetSpellProcEvent(spellInfo->Id);
-
- // Get EventProcFlag
- uint32 EventProcFlag;
- if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags
- EventProcFlag = spellProcEvent->procFlags;
- else
- EventProcFlag = spellInfo->ProcFlags; // else get from spell proto
- // Continue if no trigger exist
- if (!EventProcFlag)
- return false;
-
- // Check spellProcEvent data requirements
- if (!sSpellMgr->IsSpellProcEventCanTriggeredBy(spellInfo, spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
- return false;
- // In most cases req get honor or XP from kill
- if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER)
- {
- bool allow = false;
-
- if (victim)
- allow = ToPlayer()->isHonorOrXPTarget(victim);
-
- // Shadow Word: Death - can trigger from every kill
- if (aura->GetId() == 32409)
- allow = true;
- if (!allow)
- return false;
- }
- // Aura added by spell can`t trigger from self (prevent drop charges/do triggers)
- // But except periodic and kill triggers (can triggered from self)
- if (procSpell && procSpell->Id == spellInfo->Id
- && !(spellInfo->ProcFlags&(PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL)))
- return false;
-
- // Check if current equipment allows aura to proc
- if (!isVictim && GetTypeId() == TYPEID_PLAYER)
- {
- Player* player = ToPlayer();
- if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON)
- {
- Item* item = NULL;
- if (attType == BASE_ATTACK || attType == RANGED_ATTACK)
- item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
- else if (attType == OFF_ATTACK)
- item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
-
- if (player->IsInFeralForm())
- return false;
-
- if (!item || item->IsBroken() || item->GetTemplate()->GetClass() != ITEM_CLASS_WEAPON || !((1 << item->GetTemplate()->GetSubClass()) & spellInfo->EquippedItemSubClassMask))
- return false;
- }
- else if (spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR)
- {
- // Check if player is wearing shield
- Item* item = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
- if (!item || item->IsBroken() || item->GetTemplate()->GetClass() != ITEM_CLASS_ARMOR || !((1 << item->GetTemplate()->GetSubClass()) & spellInfo->EquippedItemSubClassMask))
- return false;
- }
- }
-
- return true;
-}
-
-bool Unit::RollProcResult(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, SpellProcEventEntry const* spellProcEvent)
-{
- SpellInfo const* spellInfo = aura->GetSpellInfo();
- // Get chance from spell
- float chance = float(spellInfo->ProcChance);
- // If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance;
- if (spellProcEvent && spellProcEvent->customChance)
- chance = spellProcEvent->customChance;
- // If PPM exist calculate chance from PPM
- if (spellProcEvent && spellProcEvent->ppmRate != 0)
- {
- if (!isVictim)
- {
- uint32 weaponSpeed = GetBaseAttackTime(attType);
- chance = GetPPMProcChance(weaponSpeed, spellProcEvent->ppmRate, spellInfo);
- }
- else if (victim)
- {
- uint32 weaponSpeed = victim->GetBaseAttackTime(attType);
- chance = victim->GetPPMProcChance(weaponSpeed, spellProcEvent->ppmRate, spellInfo);
- }
- }
-
- if (spellInfo->ProcBasePPM > 0.0f)
- chance = aura->CalcPPMProcChance(isVictim ? victim : this);
-
- // Apply chance modifer aura
- if (Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance);
-
- return roll_chance_f(chance);
-}
-
-bool Unit::HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura)
-{
- // aura can be deleted at casts
- SpellInfo const* spellProto = triggeredByAura->GetSpellInfo();
- uint32 triggered_spell_id = 0;
- int32 heal = triggeredByAura->GetAmount();
- ObjectGuid caster_guid = triggeredByAura->GetCasterGUID();
-
- // Currently only Prayer of Mending
- if (!triggered_spell_id)
- {
- TC_LOG_DEBUG("spells", "Unit::HandleAuraRaidProcFromChargeWithValue, received not handled spell: %u", spellProto->Id);
- return false;
- }
-
- // jumps
- int32 jumps = triggeredByAura->GetBase()->GetCharges() - 1;
-
- // current aura expire
- triggeredByAura->GetBase()->SetCharges(1); // will removed at next charges decrease
-
- // next target selection
- if (jumps > 0)
- {
- if (Unit* caster = triggeredByAura->GetCaster())
- {
- SpellEffectInfo const* effect = triggeredByAura->GetSpellEffectInfo();
- float radius = effect->CalcRadius(caster);
-
- if (Unit* target = GetNextRandomRaidMemberOrPet(radius))
- {
- CastCustomSpell(target, spellProto->Id, &heal, NULL, NULL, true, NULL, triggeredByAura, caster_guid);
- if (Aura* aura = target->GetAura(spellProto->Id, caster->GetGUID()))
- aura->SetCharges(jumps);
- }
- }
- }
-
- CastSpell(this, triggered_spell_id, true, NULL, triggeredByAura, caster_guid);
- return true;
-}
-
-bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura)
-{
- // aura can be deleted at casts
- SpellInfo const* spellProto = triggeredByAura->GetSpellInfo();
-
- uint32 damageSpellId;
- switch (spellProto->Id)
- {
- case 57949: // shiver
- damageSpellId = 57952;
- //animationSpellId = 57951; dummy effects for jump spell have unknown use (see also 41637)
- break;
- case 59978: // shiver
- damageSpellId = 59979;
- break;
- case 43593: // Cold Stare
- damageSpellId = 43594;
- break;
- default:
- TC_LOG_ERROR("entities.unit", "Unit::HandleAuraRaidProcFromCharge, received unhandled spell: %u", spellProto->Id);
- return false;
- }
-
- ObjectGuid caster_guid = triggeredByAura->GetCasterGUID();
-
- // jumps
- int32 jumps = triggeredByAura->GetBase()->GetCharges()-1;
-
- // current aura expire
- triggeredByAura->GetBase()->SetCharges(1); // will removed at next charges decrease
-
- // next target selection
- if (jumps > 0)
- {
- if (Unit* caster = triggeredByAura->GetCaster())
- {
- SpellEffectInfo const* effect = triggeredByAura->GetSpellEffectInfo();
- float radius = effect->CalcRadius(caster);
- if (Unit* target= GetNextRandomRaidMemberOrPet(radius))
- {
- CastSpell(target, spellProto, true, NULL, triggeredByAura, caster_guid);
- if (Aura* aura = target->GetAura(spellProto->Id, caster->GetGUID()))
- aura->SetCharges(jumps);
- }
- }
- }
-
- CastSpell(this, damageSpellId, true, NULL, triggeredByAura, caster_guid);
-
- return true;
-}
-
void Unit::SendDurabilityLoss(Player* receiver, uint32 percent)
{
WorldPackets::Misc::DurabilityDamageDeath packet;
@@ -11764,14 +11026,17 @@ 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())
+ {
+ // proc only once for victim
if (Unit* owner = GetOwner())
- owner->ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0);
+ 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 (!victim->IsCritter())
- ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
+ ProcSkillsAndAuras(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->ProcDamageAndSpell(NULL, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, BASE_ATTACK, 0);
+ victim->ProcSkillsAndAuras(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
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 44526ba491e..7d4be3b5756 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -87,45 +87,47 @@ enum SpellAuraInterruptFlags : uint32
AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE)
};
-enum SpellModOp
+enum SpellModOp : uint8
{
- SPELLMOD_DAMAGE = 0,
- SPELLMOD_DURATION = 1,
- SPELLMOD_THREAT = 2,
- SPELLMOD_EFFECT1 = 3,
- SPELLMOD_CHARGES = 4,
- SPELLMOD_RANGE = 5,
- SPELLMOD_RADIUS = 6,
- SPELLMOD_CRITICAL_CHANCE = 7,
- SPELLMOD_ALL_EFFECTS = 8,
- SPELLMOD_NOT_LOSE_CASTING_TIME = 9,
- SPELLMOD_CASTING_TIME = 10,
- SPELLMOD_COOLDOWN = 11,
- SPELLMOD_EFFECT2 = 12,
- SPELLMOD_IGNORE_ARMOR = 13,
- SPELLMOD_COST = 14, // Used when SpellPowerEntry::PowerIndex == 0
- SPELLMOD_CRIT_DAMAGE_BONUS = 15,
- SPELLMOD_RESIST_MISS_CHANCE = 16,
- SPELLMOD_JUMP_TARGETS = 17,
- SPELLMOD_CHANCE_OF_SUCCESS = 18,
- SPELLMOD_ACTIVATION_TIME = 19,
- SPELLMOD_DAMAGE_MULTIPLIER = 20,
- SPELLMOD_GLOBAL_COOLDOWN = 21,
- SPELLMOD_DOT = 22,
- SPELLMOD_EFFECT3 = 23,
- SPELLMOD_BONUS_MULTIPLIER = 24,
+ SPELLMOD_DAMAGE = 0,
+ SPELLMOD_DURATION = 1,
+ SPELLMOD_THREAT = 2,
+ SPELLMOD_EFFECT1 = 3,
+ SPELLMOD_CHARGES = 4,
+ SPELLMOD_RANGE = 5,
+ SPELLMOD_RADIUS = 6,
+ SPELLMOD_CRITICAL_CHANCE = 7,
+ SPELLMOD_ALL_EFFECTS = 8,
+ SPELLMOD_NOT_LOSE_CASTING_TIME = 9,
+ SPELLMOD_CASTING_TIME = 10,
+ SPELLMOD_COOLDOWN = 11,
+ SPELLMOD_EFFECT2 = 12,
+ SPELLMOD_IGNORE_ARMOR = 13,
+ SPELLMOD_COST = 14, // Used when SpellPowerEntry::PowerIndex == 0
+ SPELLMOD_CRIT_DAMAGE_BONUS = 15,
+ SPELLMOD_RESIST_MISS_CHANCE = 16,
+ SPELLMOD_JUMP_TARGETS = 17,
+ SPELLMOD_CHANCE_OF_SUCCESS = 18,
+ SPELLMOD_ACTIVATION_TIME = 19,
+ SPELLMOD_DAMAGE_MULTIPLIER = 20,
+ SPELLMOD_GLOBAL_COOLDOWN = 21,
+ SPELLMOD_DOT = 22,
+ SPELLMOD_EFFECT3 = 23,
+ SPELLMOD_BONUS_MULTIPLIER = 24,
// spellmod 25
- SPELLMOD_PROC_PER_MINUTE = 26,
- SPELLMOD_VALUE_MULTIPLIER = 27,
- SPELLMOD_RESIST_DISPEL_CHANCE = 28,
- SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
- SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30,
- SPELLMOD_STACK_AMOUNT = 31, // has no effect on tooltip parsing
- SPELLMOD_EFFECT4 = 32,
- SPELLMOD_EFFECT5 = 33,
- SPELLMOD_SPELL_COST2 = 34, // Used when SpellPowerEntry::PowerIndex == 1
- SPELLMOD_JUMP_DISTANCE = 35,
- SPELLMOD_STACK_AMOUNT2 = 37 // same as SPELLMOD_STACK_AMOUNT but affects tooltips
+ SPELLMOD_PROC_PER_MINUTE = 26,
+ SPELLMOD_VALUE_MULTIPLIER = 27,
+ SPELLMOD_RESIST_DISPEL_CHANCE = 28,
+ SPELLMOD_CRIT_DAMAGE_BONUS_2 = 29, //one not used spell
+ SPELLMOD_SPELL_COST_REFUND_ON_FAIL = 30,
+ SPELLMOD_STACK_AMOUNT = 31, // has no effect on tooltip parsing
+ SPELLMOD_EFFECT4 = 32,
+ SPELLMOD_EFFECT5 = 33,
+ SPELLMOD_SPELL_COST2 = 34, // Used when SpellPowerEntry::PowerIndex == 1
+ SPELLMOD_JUMP_DISTANCE = 35,
+ // spellmod 36
+ SPELLMOD_STACK_AMOUNT2 = 37 // same as SPELLMOD_STACK_AMOUNT but affects tooltips
+ // spellmod 38
};
#define MAX_SPELLMOD 39
@@ -317,7 +319,7 @@ enum TriggerCastFlags : uint32
TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state
TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions
TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements
- TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default)
+ // reuse 0x00020000
TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions
TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements
TRIGGERED_IGNORE_TARGET_CHECK = 0x00100000, //! Will ignore most target checks (mostly DBC target checks)
@@ -541,13 +543,13 @@ struct DiminishingReturn
: DRGroup(group), stack(0), hitTime(t), hitCount(count)
{ }
- DiminishingGroup DRGroup:16;
- uint16 stack:16;
+ DiminishingGroup DRGroup;
+ uint16 stack;
uint32 hitTime;
uint32 hitCount;
};
-enum MeleeHitOutcome
+enum MeleeHitOutcome : uint8
{
MELEE_HIT_EVADE, MELEE_HIT_MISS, MELEE_HIT_DODGE, MELEE_HIT_BLOCK, MELEE_HIT_PARRY,
MELEE_HIT_GLANCING, MELEE_HIT_CRIT, MELEE_HIT_CRUSHING, MELEE_HIT_NORMAL
@@ -555,21 +557,18 @@ enum MeleeHitOutcome
class DispelInfo
{
-public:
- explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
- _dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) { }
+ public:
+ explicit DispelInfo(Unit* dispeller, uint32 dispellerSpellId, uint8 chargesRemoved) :
+ _dispellerUnit(dispeller), _dispellerSpell(dispellerSpellId), _chargesRemoved(chargesRemoved) { }
- Unit* GetDispeller() const { return _dispellerUnit; }
- uint32 GetDispellerSpellId() const { return _dispellerSpell; }
- uint8 GetRemovedCharges() const { return _chargesRemoved; }
- void SetRemovedCharges(uint8 amount)
- {
- _chargesRemoved = amount;
- }
-private:
- Unit* _dispellerUnit;
- uint32 _dispellerSpell;
- uint8 _chargesRemoved;
+ Unit* GetDispeller() const { return _dispellerUnit; }
+ uint32 GetDispellerSpellId() const { return _dispellerSpell; }
+ uint8 GetRemovedCharges() const { return _chargesRemoved; }
+ void SetRemovedCharges(uint8 amount) { _chargesRemoved = amount; }
+ private:
+ Unit* _dispellerUnit;
+ uint32 _dispellerSpell;
+ uint8 _chargesRemoved;
};
struct CleanDamage
@@ -589,104 +588,106 @@ struct SpellNonMeleeDamage;
class TC_GAME_API DamageInfo
{
-private:
- Unit* const m_attacker;
- Unit* const m_victim;
- uint32 m_damage;
- SpellInfo const* const m_spellInfo;
- SpellSchoolMask const m_schoolMask;
- DamageEffectType const m_damageType;
- WeaponAttackType m_attackType;
- uint32 m_absorb;
- uint32 m_resist;
- uint32 m_block;
- uint32 m_hitMask;
-public:
- DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType);
- explicit DamageInfo(CalcDamageInfo const& dmgInfo);
- DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType);
-
- void ModifyDamage(int32 amount);
- void AbsorbDamage(uint32 amount);
- void ResistDamage(uint32 amount);
- void BlockDamage(uint32 amount);
-
- Unit* GetAttacker() const { return m_attacker; }
- Unit* GetVictim() const { return m_victim; }
- SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
- SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }
- DamageEffectType GetDamageType() const { return m_damageType; }
- WeaponAttackType GetAttackType() const { return m_attackType; }
- uint32 GetDamage() const { return m_damage; }
- uint32 GetAbsorb() const { return m_absorb; }
- uint32 GetResist() const { return m_resist; }
- uint32 GetBlock() const { return m_block; }
-
- uint32 GetHitMask() const;
+ private:
+ Unit* const m_attacker;
+ Unit* const m_victim;
+ uint32 m_damage;
+ SpellInfo const* const m_spellInfo;
+ SpellSchoolMask const m_schoolMask;
+ DamageEffectType const m_damageType;
+ WeaponAttackType m_attackType;
+ uint32 m_absorb;
+ uint32 m_resist;
+ uint32 m_block;
+ uint32 m_hitMask;
+ public:
+ DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType);
+ explicit DamageInfo(CalcDamageInfo const& dmgInfo);
+ DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask);
+
+ void ModifyDamage(int32 amount);
+ void AbsorbDamage(uint32 amount);
+ void ResistDamage(uint32 amount);
+ void BlockDamage(uint32 amount);
+
+ Unit* GetAttacker() const { return m_attacker; }
+ Unit* GetVictim() const { return m_victim; }
+ SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
+ SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }
+ DamageEffectType GetDamageType() const { return m_damageType; }
+ WeaponAttackType GetAttackType() const { return m_attackType; }
+ uint32 GetDamage() const { return m_damage; }
+ uint32 GetAbsorb() const { return m_absorb; }
+ uint32 GetResist() const { return m_resist; }
+ uint32 GetBlock() const { return m_block; }
+
+ uint32 GetHitMask() const;
};
class TC_GAME_API HealInfo
{
-private:
- Unit* const _healer;
- Unit* const _target;
- uint32 _heal;
- uint32 _effectiveHeal;
- uint32 _absorb;
- SpellInfo const* const _spellInfo;
- SpellSchoolMask const _schoolMask;
- uint32 _hitMask;
+ private:
+ Unit* const _healer;
+ Unit* const _target;
+ uint32 _heal;
+ uint32 _effectiveHeal;
+ uint32 _absorb;
+ SpellInfo const* const _spellInfo;
+ SpellSchoolMask const _schoolMask;
+ uint32 _hitMask;
-public:
- explicit HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask);
+ public:
+ HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask);
- void AbsorbHeal(uint32 amount);
- void SetEffectiveHeal(uint32 amount) { _effectiveHeal = amount; }
+ void AbsorbHeal(uint32 amount);
+ void SetEffectiveHeal(uint32 amount) { _effectiveHeal = amount; }
- Unit* GetHealer() const { return _healer; }
- Unit* GetTarget() const { return _target; }
- uint32 GetHeal() const { return _heal; }
- uint32 GetEffectiveHeal() const { return _effectiveHeal; }
- uint32 GetAbsorb() const { return _absorb; }
- SpellInfo const* GetSpellInfo() const { return _spellInfo; };
- SpellSchoolMask GetSchoolMask() const { return _schoolMask; };
+ Unit* GetHealer() const { return _healer; }
+ Unit* GetTarget() const { return _target; }
+ uint32 GetHeal() const { return _heal; }
+ uint32 GetEffectiveHeal() const { return _effectiveHeal; }
+ uint32 GetAbsorb() const { return _absorb; }
+ SpellInfo const* GetSpellInfo() const { return _spellInfo; };
+ SpellSchoolMask GetSchoolMask() const { return _schoolMask; };
- uint32 GetHitMask() const;
+ uint32 GetHitMask() const;
};
class TC_GAME_API ProcEventInfo
{
-public:
- ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask,
- uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask,
- Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
+ public:
+ ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask,
+ uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask,
+ Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo);
- Unit* GetActor() { return _actor; }
- Unit* GetActionTarget() const { return _actionTarget; }
- Unit* GetProcTarget() const { return _procTarget; }
+ Unit* GetActor() { return _actor; }
+ Unit* GetActionTarget() const { return _actionTarget; }
+ Unit* GetProcTarget() const { return _procTarget; }
- uint32 GetTypeMask() const { return _typeMask; }
- uint32 GetSpellTypeMask() const { return _spellTypeMask; }
- uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
- uint32 GetHitMask() const { return _hitMask; }
+ uint32 GetTypeMask() const { return _typeMask; }
+ uint32 GetSpellTypeMask() const { return _spellTypeMask; }
+ uint32 GetSpellPhaseMask() const { return _spellPhaseMask; }
+ uint32 GetHitMask() const { return _hitMask; }
- SpellInfo const* GetSpellInfo() const;
- SpellSchoolMask GetSchoolMask() const;
+ SpellInfo const* GetSpellInfo() const;
+ SpellSchoolMask GetSchoolMask() const;
- DamageInfo* GetDamageInfo() const { return _damageInfo; }
- HealInfo* GetHealInfo() const { return _healInfo; }
+ DamageInfo* GetDamageInfo() const { return _damageInfo; }
+ HealInfo* GetHealInfo() const { return _healInfo; }
-private:
- Unit* const _actor;
- Unit* const _actionTarget;
- Unit* const _procTarget;
- uint32 _typeMask;
- uint32 _spellTypeMask;
- uint32 _spellPhaseMask;
- uint32 _hitMask;
- Spell* _spell;
- DamageInfo* _damageInfo;
- HealInfo* _healInfo;
+ Spell const* GetProcSpell() const { return _spell; }
+
+ private:
+ Unit* const _actor;
+ Unit* const _actionTarget;
+ Unit* const _procTarget;
+ uint32 _typeMask;
+ uint32 _spellTypeMask;
+ uint32 _spellPhaseMask;
+ uint32 _hitMask;
+ Spell* _spell;
+ DamageInfo* _damageInfo;
+ HealInfo* _healInfo;
};
// Struct for use in Unit::CalculateMeleeDamage
@@ -706,7 +707,6 @@ struct CalcDamageInfo
WeaponAttackType attackType; //
uint32 procAttacker;
uint32 procVictim;
- uint32 procEx;
uint32 cleanDamage; // Used only for rage calculation
MeleeHitOutcome hitOutCome; /// @todo remove this field (need use TargetState)
};
@@ -747,7 +747,7 @@ struct SpellPeriodicAuraLogInfo
bool critical;
};
-uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
+uint32 createProcHitMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
struct RedirectThreatInfo
{
@@ -939,8 +939,6 @@ enum PlayerTotemType
#define ATTACK_DISPLAY_DELAY 200
#define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player
-struct SpellProcEventEntry; // used only privately
-
class TC_GAME_API Unit : public WorldObject
{
public:
@@ -963,6 +961,8 @@ class TC_GAME_API Unit : public WorldObject
typedef std::list<AuraApplication *> AuraApplicationList;
typedef std::list<DiminishingReturn> Diminishing;
+ typedef std::deque<std::pair<uint32 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer;
+
struct VisibleAuraSlotCompare { bool operator()(AuraApplication* left, AuraApplication* right) const; };
typedef std::set<AuraApplication*, VisibleAuraSlotCompare> VisibleAuraContainer;
@@ -1160,18 +1160,19 @@ class TC_GAME_API Unit : public WorldObject
uint32 DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage = NULL, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = NULL, bool durabilityLoss = true);
void Kill(Unit* victim, bool durabilityLoss = true);
void KillSelf(bool durabilityLoss = true) { Kill(this, durabilityLoss); }
- int32 DealHeal(Unit* victim, uint32 addhealth);
+ void DealHeal(HealInfo& healInfo);
- void ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellInfo const* procSpell = NULL, SpellInfo const* procAura = NULL);
- void ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellInfo const* procSpell, uint32 damage, SpellInfo const* procAura = NULL);
+ void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
+ uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell,
+ DamageInfo* damageInfo, HealInfo* healInfo);
- void GetProcAurasTriggeredOnEvent(AuraApplicationList& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo eventInfo);
+ void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer& aurasTriggeringProc, AuraApplicationList* procAuras, ProcEventInfo& eventInfo);
void TriggerAurasProcOnEvent(CalcDamageInfo& damageInfo);
void TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplicationList* targetProcAuras,
Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget,
uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell,
DamageInfo* damageInfo, HealInfo* healInfo);
- void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationList& procAuras);
+ void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& procAuras);
void HandleEmoteCommand(uint32 anim_id);
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false);
@@ -1205,7 +1206,7 @@ class TC_GAME_API Unit : public WorldObject
virtual uint32 GetBlockPercent() const { return 30; }
float GetWeaponProcChance() const;
- float GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellInfo* spellProto) const;
+ float GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spellProto) const;
MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const;
@@ -1262,9 +1263,9 @@ class TC_GAME_API Unit : public WorldObject
virtual void UpdateUnderwaterState(Map* m, float x, float y, float z);
bool isInAccessiblePlaceFor(Creature const* c) const;
- void SendHealSpellLog(Unit* victim, uint32 spellID, uint32 health, uint32 overHeal, uint32 absorbed, bool crit = false);
- int32 HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical = false);
- void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, int32 overEnergize, Powers powertype);
+ void SendHealSpellLog(HealInfo& healInfo, bool critical = false);
+ int32 HealBySpell(HealInfo& healInfo, bool critical = false);
+ void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, int32 overEnergize, Powers powerType);
void EnergizeBySpell(Unit* victim, uint32 SpellID, int32 Damage, Powers powertype);
void CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo, CustomSpellValues const* value, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, ObjectGuid originalCaster = ObjectGuid::Empty);
@@ -1764,7 +1765,7 @@ class TC_GAME_API Unit : public WorldObject
uint32 CalcArmorReducedDamage(Unit* attacker, Unit* victim, const uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK);
uint32 CalcSpellResistance(Unit* victim, SpellSchoolMask schoolMask, SpellInfo const* spellInfo) const;
void CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint32 const damage, uint32* absorb, uint32* resist, SpellInfo const* spellInfo = NULL);
- void CalcHealAbsorb(Unit* victim, SpellInfo const* spellInfo, uint32& healAmount, uint32& absorb);
+ void CalcHealAbsorb(HealInfo& healInfo);
void UpdateSpeed(UnitMoveType mtype);
float GetSpeed(UnitMoveType mtype) const;
@@ -1823,7 +1824,7 @@ class TC_GAME_API Unit : public WorldObject
void UpdateAuraForGroup();
// proc trigger system
- bool CanProc() const {return !m_procDeep;}
+ bool CanProc() const { return !m_procDeep; }
void SetCantProc(bool apply);
// pet auras
@@ -2001,14 +2002,8 @@ class TC_GAME_API Unit : public WorldObject
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
void DisableSpline();
+
private:
- bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent);
- bool RollProcResult(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, SpellProcEventEntry const* spellProcEvent);
- bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx);
- bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx);
- bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell);
- bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura);
- bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura);
void UpdateSplineMovement(uint32 t_diff);
void UpdateSplinePosition();
@@ -2017,6 +2012,8 @@ class TC_GAME_API Unit : public WorldObject
float GetCombatRatingReduction(CombatRating cr) const;
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const;
+ void ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType);
+
protected:
void SetFeared(bool apply);
void SetConfused(bool apply);
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 5ef380758ae..7139b9573fd 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -4586,7 +4586,7 @@ enum DiminishingReturnsType
};
// Diminishing Return Groups
-enum DiminishingGroup
+enum DiminishingGroup : uint16
{
DIMINISHING_NONE = 0,
DIMINISHING_ROOT = 1,
@@ -4845,7 +4845,7 @@ enum MailResponseResult
MAIL_ERR_ITEM_HAS_EXPIRED = 21
};
-enum SpellFamilyNames
+enum SpellFamilyNames : uint8
{
SPELLFAMILY_GENERIC = 0,
SPELLFAMILY_EVENTS = 1, // events, holidays
diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h
index 8e550534d45..5738fa91e06 100644
--- a/src/server/game/Spells/Auras/SpellAuraDefines.h
+++ b/src/server/game/Spells/Auras/SpellAuraDefines.h
@@ -290,9 +290,9 @@ enum AuraType
SPELL_AURA_MOD_RATING_FROM_STAT = 220,
SPELL_AURA_MOD_DETAUNT = 221,
SPELL_AURA_222 = 222,
- SPELL_AURA_RAID_PROC_FROM_CHARGE = 223,
+ SPELL_AURA_223 = 223, // old SPELL_AURA_RAID_PROC_FROM_CHARGE
SPELL_AURA_224 = 224,
- SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE = 225,
+ SPELL_AURA_MOD_VISIBILITY_RANGE = 225,
SPELL_AURA_PERIODIC_DUMMY = 226,
SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE = 227,
SPELL_AURA_DETECT_STEALTH = 228,
@@ -395,7 +395,7 @@ enum AuraType
SPELL_AURA_325 = 325, // Not used in 4.3.4
SPELL_AURA_PHASE_GROUP = 326, // Puts the player in all the phases that are in the group with id = miscB
SPELL_AURA_327 = 327, // Not used in 4.3.4
- SPELL_AURA_PROC_ON_POWER_AMOUNT = 328,
+ SPELL_AURA_TRIGGER_SPELL_ON_POWER_PCT = 328, // NYI Triggers spell when power goes above (MiscB = 0) or falls below (MiscB = 1) specified percent value (once, not every time condition has meet)
SPELL_AURA_MOD_POWER_GAIN_PCT = 329, // NYI
SPELL_AURA_CAST_WHILE_WALKING = 330,
SPELL_AURA_FORCE_WEATHER = 331,
@@ -463,7 +463,7 @@ enum AuraType
SPELL_AURA_393 = 393,
SPELL_AURA_SHOW_CONFIRMATION_PROMPT = 394,
SPELL_AURA_AREA_TRIGGER = 395, // NYI
- SPELL_AURA_PROC_ON_POWER_AMOUNT_2 = 396, // missing MicValueB handling, probably OnAmountReach ascending/descending or spell/stack add/remove
+ SPELL_AURA_TRIGGER_SPELL_ON_POWER_AMOUNT = 396, // NYI Triggers spell when health goes above (MiscA = 0) or falls below (MiscA = 1) specified percent value (once, not every time condition has meet)
SPELL_AURA_397 = 397,
SPELL_AURA_398 = 398,
SPELL_AURA_399 = 399,
@@ -535,7 +535,7 @@ enum AuraType
SPELL_AURA_MOD_BONUS_ARMOR = 465, // NYI
SPELL_AURA_MOD_BONUS_ARMOR_PCT = 466, // Affects bonus armor gain from all sources except base stats
SPELL_AURA_MOD_STAT_BONUS_PCT = 467, // Affects stat gain from all sources except base stats
- SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_BELOW_PCT = 468, // Triggers spell when health falls below specified percent value (once, not every time damage is taken below threshold)
+ SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_PCT = 468, // Triggers spell when health goes above (MiscA = 0) or falls below (MiscA = 1) specified percent value (once, not every time condition has meet)
SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY = 469,
SPELL_AURA_470 = 470,
SPELL_AURA_MOD_VERSATILITY = 471, // NYI
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 43c6e5f5ab6..38157d5f4d3 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -107,8 +107,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY
&AuraEffect::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY
&AuraEffect::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY
- &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell
- &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor
+ &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in AuraEffect::HandleProc
+ &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in AuraEffect::HandleProc
&AuraEffect::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES
&AuraEffect::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES
&AuraEffect::HandleNULL, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a)
@@ -288,9 +288,9 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleModRatingFromStat, //220 SPELL_AURA_MOD_RATING_FROM_STAT
&AuraEffect::HandleNULL, //221 SPELL_AURA_MOD_DETAUNT
&AuraEffect::HandleUnused, //222 unused (3.2.0) only for spell 44586 that not used in real spell cast
- &AuraEffect::HandleNoImmediateEffect, //223 SPELL_AURA_RAID_PROC_FROM_CHARGE
+ &AuraEffect::HandleUnused, //223 unused (7.2.0)
&AuraEffect::HandleUnused, //224 unused (4.3.4)
- &AuraEffect::HandleNoImmediateEffect, //225 SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE
+ &AuraEffect::HandleNULL, //225 SPELL_AURA_MOD_VISIBILITY_RANGE
&AuraEffect::HandleNoImmediateEffect, //226 SPELL_AURA_PERIODIC_DUMMY implemented in AuraEffect::PeriodicTick
&AuraEffect::HandleNoImmediateEffect, //227 SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE implemented in AuraEffect::PeriodicTick
&AuraEffect::HandleNoImmediateEffect, //228 SPELL_AURA_DETECT_STEALTH stealth detection
@@ -327,7 +327,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleUnused, //259 unused (4.3.4) old SPELL_AURA_MOD_HOT_PCT
&AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code
&AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE
- &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in spell::cancast
+ &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in Spell::CheckCast
&AuraEffect::HandleAuraAllowOnlyAbility, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask
&AuraEffect::HandleUnused, //264 unused (3.2.0)
&AuraEffect::HandleUnused, //265 unused (4.3.4)
@@ -393,7 +393,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleUnused, //325 unused (4.3.4)
&AuraEffect::HandlePhaseGroup, //326 SPELL_AURA_PHASE_GROUP
&AuraEffect::HandleUnused, //327 unused (4.3.4)
- &AuraEffect::HandleNoImmediateEffect, //328 SPELL_AURA_PROC_ON_POWER_AMOUNT implemented in Unit::HandleAuraProcOnPowerAmount
+ &AuraEffect::HandleNULL, //328 SPELL_AURA_TRIGGER_SPELL_ON_POWER_PCT
&AuraEffect::HandleNULL, //329 SPELL_AURA_MOD_POWER_GAIN_PCT
&AuraEffect::HandleNoImmediateEffect, //330 SPELL_AURA_CAST_WHILE_WALKING
&AuraEffect::HandleAuraForceWeather, //331 SPELL_AURA_FORCE_WEATHER
@@ -461,7 +461,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNULL, //393
&AuraEffect::HandleShowConfirmationPrompt, //394 SPELL_AURA_SHOW_CONFIRMATION_PROMPT
&AuraEffect::HandleCreateAreaTrigger, //395 SPELL_AURA_AREA_TRIGGER
- &AuraEffect::HandleNoImmediateEffect, //396 SPELL_AURA_PROC_ON_POWER_AMOUNT_2 implemented in Unit::HandleAuraProcOnPowerAmount
+ &AuraEffect::HandleNULL, //396 SPELL_AURA_TRIGGER_SPELL_ON_POWER_AMOUNT
&AuraEffect::HandleNULL, //397
&AuraEffect::HandleNULL, //398
&AuraEffect::HandleNULL, //399
@@ -533,7 +533,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNULL, //465 SPELL_AURA_MOD_BONUS_ARMOR
&AuraEffect::HandleNULL, //466 SPELL_AURA_MOD_BONUS_ARMOR_PCT
&AuraEffect::HandleModStatBonusPercent, //467 SPELL_AURA_MOD_STAT_BONUS_PCT
- &AuraEffect::HandleNULL, //468 SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_BELOW_PCT
+ &AuraEffect::HandleNULL, //468 SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_PCT
&AuraEffect::HandleShowConfirmationPrompt, //469 SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY
&AuraEffect::HandleNULL, //470
&AuraEffect::HandleNULL, //471 SPELL_AURA_MOD_VERSATILITY
@@ -786,7 +786,6 @@ void AuraEffect::CalculateSpellMod()
m_spellmod->type = GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER ? SPELLMOD_PCT : SPELLMOD_FLAT;
m_spellmod->spellId = GetId();
m_spellmod->mask = GetSpellEffectInfo()->SpellClassMask;
- m_spellmod->charges = GetBase()->GetCharges();
}
m_spellmod->value = GetAmount();
break;
@@ -1178,6 +1177,61 @@ void AuraEffect::PeriodicTick(AuraApplication * aurApp, Unit* caster) const
}
}
+bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const
+{
+ bool result = GetBase()->CallScriptCheckEffectProcHandlers(this, aurApp, eventInfo);
+ if (!result)
+ return false;
+
+ SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
+ switch (GetAuraType())
+ {
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
+ // compare mechanic
+ if (!spellInfo || static_cast<int32>(spellInfo->Mechanic) != GetMiscValue())
+ result = false;
+ break;
+ case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
+ // skip melee hits and instant cast spells
+ if (!spellInfo || !spellInfo->CalcCastTime())
+ result = false;
+ break;
+ case SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER:
+ // Compare casters
+ if (GetCasterGUID() != eventInfo.GetActor()->GetGUID())
+ result = false;
+ break;
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL:
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
+ {
+ // Skip melee hits and spells with wrong school or zero cost
+ if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue()) // School Check
+ || !eventInfo.GetProcSpell())
+ {
+ result = false;
+ break;
+ }
+
+ // Costs Check
+ std::vector<SpellPowerCost> const& costs = eventInfo.GetProcSpell()->GetPowerCost();
+ auto m = std::find_if(costs.begin(), costs.end(), [](SpellPowerCost const& cost) { return cost.Amount > 0; });
+ if (m == costs.end())
+ result = false;
+ break;
+ }
+ case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
+ // Skip melee hits and spells with wrong school
+ if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue()))
+ result = false;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo);
@@ -1186,6 +1240,16 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
switch (GetAuraType())
{
+ // CC Auras which use their amount to drop
+ // Are there any more auras which need this?
+ case SPELL_AURA_MOD_CONFUSE:
+ case SPELL_AURA_MOD_FEAR:
+ case SPELL_AURA_MOD_STUN:
+ case SPELL_AURA_MOD_ROOT:
+ case SPELL_AURA_TRANSFORM:
+ HandleBreakableCCAuraProc(aurApp, eventInfo);
+ break;
+ case SPELL_AURA_DUMMY:
case SPELL_AURA_PROC_TRIGGER_SPELL:
HandleProcTriggerSpellAuraProc(aurApp, eventInfo);
break;
@@ -1195,16 +1259,6 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
HandleProcTriggerDamageAuraProc(aurApp, eventInfo);
break;
- case SPELL_AURA_RAID_PROC_FROM_CHARGE:
- HandleRaidProcFromChargeAuraProc(aurApp, eventInfo);
- break;
- case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE:
- HandleRaidProcFromChargeWithValueAuraProc(aurApp, eventInfo);
- break;
- case SPELL_AURA_PROC_ON_POWER_AMOUNT:
- case SPELL_AURA_PROC_ON_POWER_AMOUNT_2:
- HandleProcTriggerSpellOnPowerAmountAuraProc(aurApp, eventInfo);
- break;
default:
break;
}
@@ -5357,8 +5411,10 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster)
if (caster)
{
int32 heal = caster->CountPctFromMaxHealth(10);
- caster->HealBySpell(target, auraSpellInfo, heal);
+ HealInfo healInfo(caster, target, heal, auraSpellInfo, auraSpellInfo->GetSchoolMask());
+ caster->HealBySpell(healInfo);
+ /// @todo: should proc other auras?
if (int32 mana = caster->GetMaxPower(POWER_MANA))
{
mana /= 10;
@@ -5723,12 +5779,14 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
damage = uint32(target->CountPctFromMaxHealth(damage));
if (!m_spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
+ {
if (GetSpellEffectInfo()->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));
}
+ }
bool crit = false;
@@ -5754,7 +5812,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
- uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
+ uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist);
if (damage)
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
@@ -5765,7 +5823,9 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit);
- caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
+ DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
+ caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
+
caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
target->SendPeriodicAuraLog(&pInfo);
}
@@ -5858,12 +5918,17 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
- uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT;
+ uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist);
if (damage)
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
+
if (caster->IsAlive())
- caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
+ {
+ DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK);
+ caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &damageInfo, nullptr);
+ }
+
int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false);
if (caster->IsAlive())
{
@@ -5872,8 +5937,11 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
uint32 heal = uint32(caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()));
heal = uint32(caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT, GetSpellEffectInfo(), GetBase()->GetStackAmount()));
- int32 gain = caster->HealBySpell(caster, GetSpellInfo(), heal);
- caster->getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellInfo());
+ HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
+ caster->HealBySpell(healInfo);
+
+ caster->getHostileRefManager().threatAssist(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);
}
caster->SendSpellNonMeleeDamageLog(&log);
@@ -5904,7 +5972,9 @@ void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster)
damage = int32(damage * gainMultiplier);
- caster->HealBySpell(target, GetSpellInfo(), damage);
+ HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
+ caster->HealBySpell(healInfo);
+ 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);
}
void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
@@ -5983,22 +6053,23 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
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());
- uint32 absorb = 0;
- uint32 heal = uint32(damage);
- caster->CalcHealAbsorb(target, GetSpellInfo(), heal, absorb);
- int32 gain = caster->DealHeal(target, heal);
+ uint32 heal = damage;
+
+ HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask());
+ caster->CalcHealAbsorb(healInfo);
+ caster->DealHeal(healInfo);
- SpellPeriodicAuraLogInfo pInfo(this, heal, heal - gain, absorb, 0, 0.0f, crit);
+ SpellPeriodicAuraLogInfo pInfo(this, heal, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
target->SendPeriodicAuraLog(&pInfo);
- target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo());
+ target->getHostileRefManager().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, GetSpellInfo());
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
- uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT;
+ uint32 hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL;
// ignore item heals
if (GetBase()->GetCastItemGUID().IsEmpty())
- caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo());
+ caster->ProcSkillsAndAuras(target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_NONE, hitMask, nullptr, nullptr, &healInfo);
}
void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const
@@ -6153,16 +6224,42 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
// Set trigger flag
uint32 procAttacker = PROC_FLAG_DONE_PERIODIC;
uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC;
- uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT;
+ uint32 hitMask = createProcHitMask(&damageInfo, SPELL_MISS_NONE);
+ uint32 spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL;
if (damageInfo.damage)
+ {
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
+ spellTypeMask |= PROC_SPELL_TYPE_DAMAGE;
+ }
- caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto);
+ DamageInfo dotDamageInfo(damageInfo, DOT, BASE_ATTACK, hitMask);
+ caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dotDamageInfo, nullptr);
caster->DealSpellDamage(&damageInfo, true);
caster->SendSpellNonMeleeDamageLog(&damageInfo);
}
+void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+{
+ DamageInfo* damageInfo = eventInfo.GetDamageInfo();
+ if (!damageInfo)
+ return;
+
+ // aura own damage at apply won't break CC
+ if (eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)
+ {
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo == GetSpellInfo())
+ return;
+ }
+
+ int32 damageLeft = GetAmount();
+ if (damageLeft < int32(damageInfo->GetDamage()))
+ aurApp->GetTarget()->RemoveAura(aurApp);
+ else
+ ChangeAmount(damageLeft - damageInfo->GetDamage());
+}
+
void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
Unit* triggerCaster = aurApp->GetTarget();
@@ -6175,7 +6272,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve
triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, NULL, this);
}
else
- TC_LOG_DEBUG("spells","AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
+ TC_LOG_ERROR("spells","AuraEffect::HandleProcTriggerSpellAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
}
void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
@@ -6191,7 +6288,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp
triggerCaster->CastCustomSpell(triggerTarget, triggerSpellId, &basepoints0, NULL, NULL, true, NULL, this);
}
else
- TC_LOG_DEBUG("spells","AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
+ TC_LOG_ERROR("spells","AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
}
void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
@@ -6208,124 +6305,6 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv
target->SendSpellNonMeleeDamageLog(&damageInfo);
}
-void AuraEffect::HandleRaidProcFromChargeAuraProc(AuraApplication* aurApp, ProcEventInfo& /*eventInfo*/)
-{
- Unit* target = aurApp->GetTarget();
-
- uint32 triggerSpellId;
- switch (GetId())
- {
- case 57949: // Shiver
- triggerSpellId = 57952;
- //animationSpellId = 57951; dummy effects for jump spell have unknown use (see also 41637)
- break;
- case 59978: // Shiver
- triggerSpellId = 59979;
- break;
- case 43593: // Cold Stare
- triggerSpellId = 43594;
- break;
- default:
- TC_LOG_DEBUG("spells", "AuraEffect::HandleRaidProcFromChargeAuraProc: received not handled spell: %u", GetId());
- return;
- }
-
- int32 jumps = GetBase()->GetCharges();
-
- // current aura expire on proc finish
- GetBase()->SetCharges(0);
- GetBase()->SetUsingCharges(true);
-
- // next target selection
- if (jumps > 0)
- {
- if (Unit* caster = GetCaster())
- {
- float radius = GetSpellEffectInfo()->CalcRadius(caster);
-
- if (Unit* triggerTarget = target->GetNextRandomRaidMemberOrPet(radius))
- {
- target->CastSpell(triggerTarget, GetSpellInfo(), true, NULL, this, GetCasterGUID());
- if (Aura* aura = triggerTarget->GetAura(GetId(), GetCasterGUID()))
- aura->SetCharges(jumps);
- }
- }
- }
-
- TC_LOG_DEBUG("spells", "AuraEffect::HandleRaidProcFromChargeAuraProc: Triggering spell %u from aura %u proc", triggerSpellId, GetId());
- target->CastSpell(target, triggerSpellId, true, NULL, this, GetCasterGUID());
-}
-
-
-void AuraEffect::HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& /*eventInfo*/)
-{
- Unit* target = aurApp->GetTarget();
-
- // Currently only Prayer of Mending
- if (!(GetSpellInfo()->SpellFamilyName == SPELLFAMILY_PRIEST && GetSpellInfo()->SpellFamilyFlags[1] & 0x20))
- {
- TC_LOG_DEBUG("spells", "AuraEffect::HandleRaidProcFromChargeWithValueAuraProc: received not handled spell: %u", GetId());
- return;
- }
- uint32 triggerSpellId = 33110;
-
- int32 value = GetAmount();
-
- int32 jumps = GetBase()->GetCharges();
-
- // current aura expire on proc finish
- GetBase()->SetCharges(0);
- GetBase()->SetUsingCharges(true);
-
- // next target selection
- if (jumps > 0)
- {
- if (Unit* caster = GetCaster())
- {
- float radius = GetSpellEffectInfo()->CalcRadius(caster);
-
- if (Unit* triggerTarget = target->GetNextRandomRaidMemberOrPet(radius))
- {
- target->CastCustomSpell(triggerTarget, GetId(), &value, NULL, NULL, true, NULL, this, GetCasterGUID());
- if (Aura* aura = triggerTarget->GetAura(GetId(), GetCasterGUID()))
- aura->SetCharges(jumps);
- }
- }
- }
-
- TC_LOG_DEBUG("spells", "AuraEffect::HandleRaidProcFromChargeWithValueAuraProc: Triggering spell %u from aura %u proc", triggerSpellId, GetId());
- target->CastCustomSpell(target, triggerSpellId, &value, NULL, NULL, true, NULL, this, GetCasterGUID());
-}
-
-void AuraEffect::HandleProcTriggerSpellOnPowerAmountAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo)
-{
- // Power amount required to proc the spell
- int32 powerAmountRequired = GetAmount();
- // Power type required to proc
- Powers powerRequired = Powers(_effectInfo->MiscValue);
-
- if (!powerRequired || !powerAmountRequired)
- {
- TC_LOG_ERROR("spells", "AuraEffect::HandleProcTriggerSpellOnPowerAmountAuraProc: Spell %u have 0 PowerAmountRequired in EffectAmount[%d] or 0 PowerRequired in EffectMiscValue", GetId(), GetEffIndex());
- return /*false*/;
- }
-
- Unit* triggerCaster = aurApp->GetTarget();
- Unit* triggerTarget = eventInfo.GetProcTarget();
-
- if (triggerCaster->GetPower(powerRequired) != powerAmountRequired)
- return /*false*/;
-
- uint32 triggerSpellId = _effectInfo->TriggerSpell;
- if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId))
- {
- TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerSpellOnPowerAmountAuraProc: Triggering spell %u from aura %u proc", triggeredSpellInfo->Id, GetId());
- triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, nullptr, this);
- }
- else
- TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerSpellOnPowerAmountAuraProc: Could not trigger spell %u from aura %u proc, because the spell does not have an entry in Spell.dbc.", triggerSpellId, GetId());
-}
-
void AuraEffect::HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mode, bool apply) const
{
if (!(mode & AURA_EFFECT_HANDLE_REAL))
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index 607a66db45d..5a56d95a3e0 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -41,7 +41,6 @@ class TC_GAME_API AuraEffect
Aura* GetBase() const { return m_base; }
void GetTargetList(std::list<Unit*> & targetList) const;
void GetApplicationList(std::list<AuraApplication*> & applicationList) const;
- SpellModifier* GetSpellModifier() const { return m_spellmod; }
SpellInfo const* GetSpellInfo() const { return m_spellInfo; }
uint32 GetId() const { return m_spellInfo->Id; }
@@ -90,8 +89,9 @@ class TC_GAME_API AuraEffect
bool HasSpellClassMask() const { return GetSpellEffectInfo()->SpellClassMask; }
void SendTickImmune(Unit* target, Unit* caster) const;
- void PeriodicTick(AuraApplication * aurApp, Unit* caster) const;
+ void PeriodicTick(AuraApplication* aurApp, Unit* caster) const;
+ bool CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const;
void HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
// add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras
@@ -325,12 +325,10 @@ class TC_GAME_API AuraEffect
void HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) const;
// aura effect proc handlers
+ void HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
void HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
- void HandleRaidProcFromChargeAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
- void HandleRaidProcFromChargeWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
- void HandleProcTriggerSpellOnPowerAmountAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo);
};
namespace Trinity
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 6cad102c206..913b0f8e2ca 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -958,12 +958,6 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode)
// reset charges
SetCharges(CalcMaxCharges());
- // FIXME: not a best way to synchronize charges, but works
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (AuraEffect* aurEff = GetEffect(i))
- if (aurEff->GetAuraType() == SPELL_AURA_ADD_FLAT_MODIFIER || aurEff->GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER)
- if (SpellModifier* mod = aurEff->GetSpellModifier())
- mod->charges = GetCharges();
}
SetNeedClientUpdateForTargets();
@@ -1178,7 +1172,7 @@ uint32 Aura::GetEffectMask() const
return effMask;
}
-void Aura::GetApplicationList(std::list<AuraApplication*> & applicationList) const
+void Aura::GetApplicationList(Unit::AuraApplicationList& applicationList) const
{
for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
{
@@ -1682,49 +1676,78 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf
}
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
-
ASSERT(procEntry);
// cooldowns should be added to the whole aura (see 51698 area aura)
AddProcCooldown(now + procEntry->Cooldown);
+
+ SetLastProcSuccessTime(now);
}
-bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const
+uint32 Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const
{
SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId());
// only auras with spell proc entry can trigger proc
if (!procEntry)
- return false;
+ return 0;
// check if we have charges to proc with
- if (IsUsingCharges() && !GetCharges())
- return false;
+ if (IsUsingCharges())
+ {
+ if (!GetCharges())
+ return 0;
+
+ if (procEntry->AttributesMask & PROC_ATTR_REQ_SPELLMOD)
+ if (Spell const* spell = eventInfo.GetProcSpell())
+ if (!spell->m_appliedMods.count(const_cast<Aura*>(this)))
+ return 0;
+ }
// check proc cooldown
if (IsProcOnCooldown(now))
- return false;
-
- /// @todo
- // something about triggered spells triggering, and add extra attack effect
+ return 0;
// do checks against db data
if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
- return false;
+ return 0;
+
+ // check if aura can proc when spell is triggered
+ if (!(procEntry->AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC))
+ if (Spell const* spell = eventInfo.GetProcSpell())
+ if (spell->IsTriggered())
+ if (!GetSpellInfo()->HasAttribute(SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED))
+ return 0;
// do checks using conditions table
if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId(), eventInfo.GetActor(), eventInfo.GetActionTarget()))
- return false;
+ return 0;
// AuraScript Hook
bool check = const_cast<Aura*>(this)->CallScriptCheckProcHandlers(aurApp, eventInfo);
if (!check)
- return false;
+ return 0;
+
+ // At least one effect has to pass checks to proc aura
+ uint32 procEffectMask = 0;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (aurApp->HasEffect(i))
+ if (GetEffect(i)->CheckEffectProc(aurApp, eventInfo))
+ procEffectMask |= (1 << i);
+
+ if (!procEffectMask)
+ return 0;
/// @todo
// do allow additional requirements for procs
// this is needed because this is the last moment in which you can prevent aura charge drop on proc
// and possibly a way to prevent default checks (if there're going to be any)
+ // Aura added by spell can't trigger from self (prevent drop charges/do triggers)
+ // But except periodic and kill triggers (can triggered from self)
+ if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (spellInfo->Id == GetId() && !(eventInfo.GetTypeMask() & (PROC_FLAG_TAKEN_PERIODIC | PROC_FLAG_KILL)))
+ return 0;
+
// Check if current equipment meets aura requirements
// do that only for passive spells
/// @todo this needs to be unified for all kinds of auras
@@ -1734,19 +1757,19 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON)
{
if (target->ToPlayer()->IsInFeralForm())
- return false;
+ return 0;
- if (eventInfo.GetDamageInfo())
+ if (DamageInfo* damageInfo = eventInfo.GetDamageInfo())
{
- WeaponAttackType attType = eventInfo.GetDamageInfo()->GetAttackType();
- Item* item = NULL;
+ WeaponAttackType attType = damageInfo->GetAttackType();
+ Item* item = nullptr;
if (attType == BASE_ATTACK || attType == RANGED_ATTACK)
item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
else if (attType == OFF_ATTACK)
item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (!item || item->IsBroken() || item->GetTemplate()->GetClass() != ITEM_CLASS_WEAPON || !((1 << item->GetTemplate()->GetSubClass()) & GetSpellInfo()->EquippedItemSubClassMask))
- return false;
+ return 0;
}
}
else if (GetSpellInfo()->EquippedItemClass == ITEM_CLASS_ARMOR)
@@ -1754,11 +1777,16 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI
// Check if player is wearing shield
Item* item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (!item || item->IsBroken() || item->GetTemplate()->GetClass() != ITEM_CLASS_ARMOR || !((1 << item->GetTemplate()->GetSubClass()) & GetSpellInfo()->EquippedItemSubClassMask))
- return false;
+ return 0;
}
}
- return roll_chance_f(CalcProcChance(*procEntry, eventInfo));
+ const_cast<Aura*>(this)->SetLastProcAttemptTime(now);
+
+ if (roll_chance_f(CalcProcChance(*procEntry, eventInfo)))
+ return procEffectMask;
+
+ return 0;
}
float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
@@ -1774,6 +1802,10 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event
uint32 WeaponSpeed = caster->GetBaseAttackTime(eventInfo.GetDamageInfo()->GetAttackType());
chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo());
}
+
+ if (GetSpellInfo()->ProcBasePPM > 0.0f)
+ chance = CalcPPMProcChance(caster);
+
// apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHANCE_OF_SUCCESS, chance);
@@ -1781,16 +1813,23 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event
return chance;
}
-void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo)
+void Aura::TriggerProcOnEvent(uint32 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo)
{
- CallScriptProcHandlers(aurApp, eventInfo);
+ bool prevented = CallScriptProcHandlers(aurApp, eventInfo);
+ if (!prevented)
+ {
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (!(procEffectMask & (1 << i)))
+ continue;
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if (aurApp->HasEffect(i))
// OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc()
- GetEffect(i)->HandleProc(aurApp, eventInfo);
+ if (aurApp->HasEffect(i))
+ GetEffect(i)->HandleProc(aurApp, eventInfo);
+ }
- CallScriptAfterProcHandlers(aurApp, eventInfo);
+ CallScriptAfterProcHandlers(aurApp, eventInfo);
+ }
// Remove aura if we've used last charge to proc
if (IsUsingCharges() && !GetCharges())
@@ -2156,6 +2195,23 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI
}
}
+bool Aura::CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
+{
+ bool result = true;
+ for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
+ {
+ (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC, aurApp);
+ auto hookItrEnd = (*scritr)->DoCheckEffectProc.end(), hookItr = (*scritr)->DoCheckEffectProc.begin();
+ for (; hookItr != hookItrEnd; ++hookItr)
+ if (hookItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ result &= hookItr->Call(*scritr, aurEff, eventInfo);
+
+ (*scritr)->_FinishScriptCall();
+ }
+
+ return result;
+}
+
bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
bool preventDefault = false;
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index 1fdfb726610..84689af94f5 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -242,18 +242,14 @@ class TC_GAME_API Aura
bool CheckAreaTarget(Unit* target);
bool CanStackWith(Aura const* existingAura) const;
- // Proc system
- // this subsystem is not yet in use - the core of it is functional, but still some research has to be done
- // and some dependant problems fixed before it can replace old proc system (for example cooldown handling)
- // currently proc system functionality is implemented in Unit::ProcDamageAndSpell
bool IsProcOnCooldown(std::chrono::steady_clock::time_point now) const;
void AddProcCooldown(std::chrono::steady_clock::time_point cooldownEnd);
bool IsUsingCharges() const { return m_isUsingCharges; }
void SetUsingCharges(bool val) { m_isUsingCharges = val; }
void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now);
- bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const;
+ uint32 IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const;
float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
- void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo);
+ void TriggerProcOnEvent(uint32 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo);
float CalcPPMProcChance(Unit* actor) const;
void SetLastProcAttemptTime(std::chrono::steady_clock::time_point lastProcAttemptTime) { m_lastProcAttemptTime = lastProcAttemptTime; }
void SetLastProcSuccessTime(std::chrono::steady_clock::time_point lastProcSuccessTime) { m_lastProcSuccessTime = lastProcSuccessTime; }
@@ -279,6 +275,7 @@ class TC_GAME_API Aura
void CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & splitAmount);
// Spell Proc Hooks
bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
+ bool CallScriptCheckEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
@@ -359,7 +356,7 @@ class TC_GAME_API UnitAura : public Aura
DiminishingGroup GetDiminishGroup() const { return m_AuraDRGroup; }
private:
- DiminishingGroup m_AuraDRGroup:8; // Diminishing
+ DiminishingGroup m_AuraDRGroup; // Diminishing
};
class TC_GAME_API DynObjAura : public Aura
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 44085cc5025..04daa7f6b98 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -607,7 +607,7 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo))
m_healing = 0;
m_procAttacker = 0;
m_procVictim = 0;
- m_procEx = 0;
+ m_hitMask = 0;
focusObject = NULL;
m_castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, m_caster->GetMapId(), m_spellInfo->Id, m_caster->GetMap()->GenerateLowGuid<HighGuid::Cast>());
memset(m_misc.Raw.Data, 0, sizeof(m_misc.Raw.Data));
@@ -2000,12 +2000,11 @@ GameObject* Spell::SearchSpellFocus()
return focus;
}
-void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
+void Spell::prepareDataForTriggerSystem()
{
//==========================================================================================
// Now fill data for trigger system, need know:
- // can spell trigger another or not (m_canTrigger)
- // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_procEx)
+ // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
//==========================================================================================
m_procVictim = m_procAttacker = 0;
@@ -2035,7 +2034,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
break;
default:
if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON &&
- m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND)
+ m_spellInfo->EquippedItemSubClassMask & (1 << ITEM_SUBCLASS_WEAPON_WAND)
&& m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
{
m_procAttacker = PROC_FLAG_DONE_RANGED_AUTO_ATTACK;
@@ -2044,7 +2043,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
// For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
// Because spell positivity is dependant on target
}
- m_procEx = PROC_EX_NONE;
+ m_hitMask = PROC_HIT_NONE;
// Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
@@ -2055,29 +2054,12 @@ void Spell::prepareDataForTriggerSystem(AuraEffect const* /*triggeredByAura*/)
m_procAttacker |= PROC_FLAG_DONE_TRAP_ACTIVATION;
}
- /* Effects which are result of aura proc from triggered spell cannot proc
- to prevent chain proc of these spells */
-
// Hellfire Effect - trigger as DOT
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000040)
{
m_procAttacker = PROC_FLAG_DONE_PERIODIC;
m_procVictim = PROC_FLAG_TAKEN_PERIODIC;
}
-
- // Ranged autorepeat attack is set as triggered spell - ignore it
- if (!(m_procAttacker & PROC_FLAG_DONE_RANGED_AUTO_ATTACK))
- {
- if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS &&
- (m_spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC) ||
- m_spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2)))
- m_procEx |= PROC_EX_INTERNAL_CANT_PROC;
- else if (_triggeredCastFlags & TRIGGERED_DISALLOW_PROC_EVENTS)
- m_procEx |= PROC_EX_INTERNAL_TRIGGERED;
- }
- // Totem casts require spellfamilymask defined in spell_proc_event to proc
- if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsTotem() && m_caster->IsControlledByPlayer())
- m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY;
}
void Spell::CleanupTargetList()
@@ -2088,6 +2070,32 @@ void Spell::CleanupTargetList()
m_delayMoment = 0;
}
+class ProcReflectDelayed : public BasicEvent
+{
+ public:
+ ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
+
+ bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
+ {
+ Unit* caster = ObjectAccessor::GetUnit(*_victim, _casterGuid);
+ if (!caster)
+ return true;
+
+ uint32 const typeMaskActor = PROC_FLAG_NONE;
+ uint32 const typeMaskActionTarget = PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG;
+ uint32 const spellTypeMask = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL;
+ uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE;
+ uint32 const hitMask = PROC_HIT_REFLECT;
+
+ caster->ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
+ return true;
+ }
+
+ private:
+ Unit* _victim;
+ ObjectGuid _casterGuid;
+};
+
void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/)
{
uint32 validEffectMask = 0;
@@ -2174,20 +2182,20 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*=
targetInfo.timeDelay = uint64(m_spellInfo->Speed * 1000.0f);
// Calculate minimum incoming time
- if (m_delayMoment == 0 || m_delayMoment > targetInfo.timeDelay)
+ if (!m_delayMoment || m_delayMoment > targetInfo.timeDelay)
m_delayMoment = targetInfo.timeDelay;
}
else
- targetInfo.timeDelay = 0LL;
+ targetInfo.timeDelay = 0ULL;
// If target reflect spell back to caster
if (targetInfo.missCondition == SPELL_MISS_REFLECT)
{
// Calculate reflected spell result on caster
- targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, m_canReflect);
+ targetInfo.reflectResult = m_caster->SpellHitResult(m_caster, m_spellInfo, false); // can't reflect twice
- if (targetInfo.reflectResult == SPELL_MISS_REFLECT) // Impossible reflect again, so simply deflect spell
- targetInfo.reflectResult = SPELL_MISS_PARRY;
+ // Proc spell reflect aura when missile hits the original target
+ target->m_Events.AddEvent(new ProcReflectDelayed(target, m_originalCasterGUID), target->m_Events.CalculateTime(targetInfo.timeDelay));
// Increase time interval for reflected spells by 1.5
targetInfo.timeDelay += targetInfo.timeDelay >> 1;
@@ -2244,7 +2252,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask)
else
target.timeDelay = uint64(m_spellInfo->Speed * 1000.0f);
- if (m_delayMoment == 0 || m_delayMoment > target.timeDelay)
+ if (!m_delayMoment || m_delayMoment > target.timeDelay)
m_delayMoment = target.timeDelay;
}
else
@@ -2356,13 +2364,13 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
uint32 procVictim = m_procVictim;
- uint32 procEx = m_procEx;
+ uint32 hitMask = m_hitMask;
- m_spellAura = NULL; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
+ m_spellAura = nullptr; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied
- //Spells with this flag cannot trigger if effect is cast on self
- bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
- Unit* spellHitTarget = NULL;
+ // Spells with this flag cannot trigger if effect is cast on self
+ bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2);
+ Unit* spellHitTarget = nullptr;
if (missInfo == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
spellHitTarget = unit;
@@ -2394,23 +2402,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo2 != SPELL_MISS_MISS)
m_caster->SendSpellMiss(unit, m_spellInfo->Id, missInfo2);
m_damage = 0;
- spellHitTarget = NULL;
+ spellHitTarget = nullptr;
}
}
// Do not take combo points on dodge and miss
- if (missInfo != SPELL_MISS_NONE && m_needComboPoints &&
- m_targets.GetUnitTargetGUID() == target->targetGUID)
- {
+ if (missInfo != SPELL_MISS_NONE && m_needComboPoints && m_targets.GetUnitTargetGUID() == target->targetGUID)
m_needComboPoints = false;
- // Restore spell mods for a miss/dodge/parry Cold Blood
- /// @todo check how broad this rule should be
- if (m_caster->GetTypeId() == TYPEID_PLAYER && (missInfo == SPELL_MISS_MISS ||
- missInfo == SPELL_MISS_DODGE || missInfo == SPELL_MISS_PARRY))
- m_caster->ToPlayer()->RestoreSpellMods(this, 14177);
- }
- // Trigger info was not filled in spell::preparedatafortriggersystem - we do it now
+ // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
if (canEffectTrigger && !procAttacker && !procVictim)
{
bool positive = true;
@@ -2457,19 +2457,20 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
uint32 addhealth = m_healing;
if (crit)
{
- procEx |= PROC_EX_CRITICAL_HIT;
- addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, NULL);
+ hitMask |= PROC_HIT_CRITICAL;
+ addhealth = caster->SpellCriticalHealingBonus(m_spellInfo, addhealth, nullptr);
}
else
- procEx |= PROC_EX_NORMAL_HIT;
+ hitMask |= PROC_HIT_NORMAL;
- int32 gain = caster->HealBySpell(unitTarget, m_spellInfo, addhealth, crit);
- unitTarget->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
- m_healing = gain;
+ HealInfo healInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo->GetSchoolMask());
+ caster->HealBySpell(healInfo, crit);
+ unitTarget->getHostileRefManager().threatAssist(caster, float(healInfo.GetEffectiveHeal()) * 0.5f, m_spellInfo);
+ m_healing = healInfo.GetEffectiveHeal();
- // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
- if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
+ // Do triggers for unit
+ if (canEffectTrigger)
+ caster->ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, this, nullptr, &healInfo);
}
// Do damage and triggers
else if (m_damage > 0)
@@ -2481,16 +2482,18 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo, m_attackType, target->crit);
caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
- procEx |= createProcExtendMask(&damageInfo, missInfo);
+ hitMask |= createProcHitMask(&damageInfo, missInfo);
procVictim |= PROC_FLAG_TAKEN_DAMAGE;
- // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
- if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
+ // Do triggers for unit
+ if (canEffectTrigger)
{
- caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
- if (caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET)) == 0 &&
+ 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);
+
+ if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) &&
(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
- caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
+ caster->ToPlayer()->CastItemCombatSpell(spellDamageInfo);
}
m_damage = damageInfo.damage;
@@ -2505,10 +2508,17 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_SpellVisual, m_spellSchoolMask);
- procEx |= createProcExtendMask(&damageInfo, missInfo);
- // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
- if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT)
- caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo, m_triggeredByAuraSpell);
+ hitMask |= createProcHitMask(&damageInfo, missInfo);
+ // Do triggers for unit
+ 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);
+
+ if (caster->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) &&
+ (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
+ caster->ToPlayer()->CastItemCombatSpell(spellNoDamageInfo);
+ }
// Failed Pickpocket, reveal rogue
if (missInfo == SPELL_MISS_RESIST && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && unitTarget->GetTypeId() == TYPEID_UNIT)
@@ -3029,7 +3039,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
}
// Prepare data for triggers
- prepareDataForTriggerSystem(triggeredByAura);
+ prepareDataForTriggerSystem();
if (Player* player = m_caster->ToPlayer())
{
@@ -3139,10 +3149,6 @@ void Spell::cancel()
SendInterrupted(0);
SendCastResult(SPELL_FAILED_INTERRUPTED);
- // spell is canceled-take mods and clear list
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->RemoveSpellMods(this);
-
m_appliedMods.clear();
break;
@@ -3380,6 +3386,25 @@ void Spell::cast(bool skipCheck)
if (Creature* creatureCaster = m_caster->ToCreature())
creatureCaster->ReleaseFocus(this);
+
+ if (!m_originalCaster)
+ return;
+
+ // Handle procs on cast
+ uint32 procAttacker = m_procAttacker;
+ if (!procAttacker)
+ {
+ if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
+ procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
+ else
+ procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
+ }
+
+ uint32 hitMask = m_hitMask;
+ 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);
}
void Spell::handle_immediate()
@@ -3534,20 +3559,6 @@ void Spell::_handle_immediate_phase()
// process items
for (std::vector<ItemTargetInfo>::iterator ihit = m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit)
DoAllEffectOnTarget(&(*ihit));
-
- if (!m_originalCaster)
- return;
- // Handle procs on cast
- /// @todo finish new proc system:P
- if (m_UniqueTargetInfo.empty() && m_targets.HasDst())
- {
- uint32 procAttacker = m_procAttacker;
- if (!procAttacker)
- procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS;
-
- // Proc the spells that have DEST target
- m_originalCaster->ProcDamageAndSpell(NULL, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell);
- }
}
void Spell::_handle_finish_phase()
@@ -3571,7 +3582,24 @@ void Spell::_handle_finish_phase()
m_caster->m_extraAttacks = 0;
}
- /// @todo trigger proc phase finish here
+ // Handle procs on finish
+ if (!m_originalCaster)
+ return;
+
+ uint32 procAttacker = m_procAttacker;
+ if (!procAttacker)
+ {
+ if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
+ procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG;
+ else
+ procAttacker = m_spellInfo->IsPositive() ? PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS : PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG;
+ }
+
+ uint32 hitMask = m_hitMask;
+ 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_FINISH, hitMask, this, nullptr, nullptr);
}
void Spell::SendSpellCooldown()
@@ -3741,18 +3769,6 @@ void Spell::finish(bool ok)
m_caster->ToPlayer()->UpdatePotionCooldown(this);
}
- if (Player* modOwner = m_caster->GetSpellModOwner())
- {
- // triggered spell pointer can be not set in some cases
- // this is needed for proper apply of triggered spell mods
- modOwner->SetSpellModTakingSpell(this, true);
-
- // Take mods after trigger spell (needed for 14177 to affect 48664)
- // mods are taken only on succesfull cast and independantly from targets of the spell
- modOwner->RemoveSpellMods(this);
- modOwner->SetSpellModTakingSpell(this, false);
- }
-
// Stop Attack for some spells
if (m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET))
m_caster->AttackStop();
@@ -7558,8 +7574,8 @@ void Spell::TriggerGlobalCooldown()
if (m_spellInfo->StartRecoveryTime >= MIN_GCD && m_spellInfo->StartRecoveryTime <= MAX_GCD)
{
// gcd modifier auras are applied only to own spells and only players have such mods
- if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this);
+ if (Player* modOwner = m_caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this);
bool isMeleeOrRangedSpell = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE ||
m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED ||
@@ -7568,10 +7584,16 @@ void Spell::TriggerGlobalCooldown()
// Apply haste rating
if (gcd > MIN_GCD && ((m_spellInfo->StartRecoveryCategory == 133 && !isMeleeOrRangedSpell) || m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE, m_spellInfo)))
- gcd = std::min<int32>(std::max<int32>(int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_HASTE)), MIN_GCD), MAX_GCD);
+ {
+ gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_HASTE));
+ RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
+ }
if (gcd > MIN_GCD && m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN, m_spellInfo))
- gcd = std::min<int32>(std::max<int32>(int32(float(gcd) * m_caster->GetFloatValue(UNIT_FIELD_MOD_HASTE_REGEN)), MIN_GCD), MAX_GCD);
+ {
+ gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_FIELD_MOD_HASTE_REGEN));
+ RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
+ }
}
m_caster->GetSpellHistory()->AddGlobalCooldown(m_spellInfo, gcd);
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index b3602e28123..881e578813e 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -478,7 +478,7 @@ class TC_GAME_API Spell
void EffectPlayScene(SpellEffIndex effIndex);
void EffectGiveHonor(SpellEffIndex effIndex);
- typedef std::set<Aura*> UsedSpellMods;
+ typedef std::unordered_set<Aura*> UsedSpellMods;
Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID = ObjectGuid::Empty, bool skipCheck = false);
~Spell();
@@ -758,8 +758,8 @@ class TC_GAME_API Spell
// ******************************************
uint32 m_procAttacker; // Attacker trigger flags
uint32 m_procVictim; // Victim trigger flags
- uint32 m_procEx;
- void prepareDataForTriggerSystem(AuraEffect const* triggeredByAura);
+ uint32 m_hitMask;
+ void prepareDataForTriggerSystem();
// *****************************************
// Spell target subsystem
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 57202975230..5bc8e7ec831 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -1348,7 +1348,8 @@ void Spell::EffectHealthLeech(SpellEffIndex /*effIndex*/)
healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL, effectInfo);
healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL, effectInfo);
- m_caster->HealBySpell(m_caster, m_spellInfo, uint32(healthGain));
+ HealInfo healInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellSchoolMask);
+ m_caster->HealBySpell(healInfo);
}
}
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 58dae0ed12a..2710df635c5 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -28,6 +28,7 @@
#include "ObjectMgr.h"
#include "Player.h"
#include "SharedDefines.h"
+#include "Spell.h"
#include "SpellAuraDefines.h"
#include "SpellInfo.h"
#include <G3D/g3dmath.h>
@@ -799,171 +800,6 @@ SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
return SPELL_GROUP_STACK_RULE_DEFAULT;
}
-SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
-{
- SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId);
- if (itr != mSpellProcEventMap.end())
- return &itr->second;
- return NULL;
-}
-
-bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const
-{
- // No extra req need
- uint32 procEvent_procEx = PROC_EX_NONE;
-
- // check prockFlags for condition
- if ((procFlags & EventProcFlag) == 0)
- return false;
-
- bool hasFamilyMask = false;
-
- /**
-
- * @brief Check auras procced by periodics
-
- *Only damaging Dots can proc auras with PROC_FLAG_TAKEN_DAMAGE
-
- *Only Dots can proc if ONLY has PROC_FLAG_DONE_PERIODIC or PROC_FLAG_TAKEN_PERIODIC.
-
- *Hots can proc if ONLY has PROC_FLAG_DONE_PERIODIC and spellfamily != 0
-
- *Only Dots can proc auras with PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG or PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG
-
- *Only Hots can proc auras with PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS or PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS
-
- *Only Dots can proc auras with PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG or PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG
-
- *Only Hots can proc auras with PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS or PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS
-
- * @param procSpell the spell proccing the aura
- * @param procFlags proc_flags of spellProc
- * @param procExtra proc_EX of procSpell
- * @param EventProcFlag proc_flags of aura to be procced
- * @param spellProto SpellInfo of aura to be procced
-
- */
-
- /// Quick Check - If PROC_FLAG_TAKEN_DAMAGE is set for aura and procSpell dealt damage, proc no matter what kind of spell that deals the damage.
- if (procFlags & PROC_FLAG_TAKEN_DAMAGE && EventProcFlag & PROC_FLAG_TAKEN_DAMAGE)
- return true;
-
- if (procFlags & PROC_FLAG_DONE_PERIODIC && EventProcFlag & PROC_FLAG_DONE_PERIODIC)
- {
- if (procExtra & PROC_EX_INTERNAL_HOT)
- {
- if (EventProcFlag == PROC_FLAG_DONE_PERIODIC)
- {
- /// no aura with only PROC_FLAG_DONE_PERIODIC and spellFamilyName == 0 can proc from a HOT.
- if (!spellProto->SpellFamilyName)
- return false;
- }
- /// Aura must have positive procflags for a HOT to proc
- else if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)))
- return false;
- }
- /// Aura must have negative or neutral(PROC_FLAG_DONE_PERIODIC only) procflags for a DOT to proc
- else if (EventProcFlag != PROC_FLAG_DONE_PERIODIC)
- if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG)))
- return false;
- }
-
- if (procFlags & PROC_FLAG_TAKEN_PERIODIC && EventProcFlag & PROC_FLAG_TAKEN_PERIODIC)
- {
- if (procExtra & PROC_EX_INTERNAL_HOT)
- {
- /// No aura that only has PROC_FLAG_TAKEN_PERIODIC can proc from a HOT.
- if (EventProcFlag == PROC_FLAG_TAKEN_PERIODIC)
- return false;
- /// Aura must have positive procflags for a HOT to proc
- if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS)))
- return false;
- }
- /// Aura must have negative or neutral(PROC_FLAG_TAKEN_PERIODIC only) procflags for a DOT to proc
- else if (EventProcFlag != PROC_FLAG_TAKEN_PERIODIC)
- if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG)))
- return false;
- }
- // Trap casts are active by default
- if (procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION)
- active = true;
-
- // Always trigger for this
- if (procFlags & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
- return true;
-
- if (spellProcEvent) // Exist event data
- {
- // Store extra req
- procEvent_procEx = spellProcEvent->procEx;
-
- // For melee triggers
- if (procSpell == NULL)
- {
- // Check (if set) for school (melee attack has Normal school)
- if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
- return false;
- }
- else // For spells need check school/spell family/family mask
- {
- // Check (if set) for school
- if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpell->SchoolMask) == 0)
- return false;
-
- // Check (if set) for spellFamilyName
- if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
- return false;
-
- // spellFamilyName is Ok need check for spellFamilyMask if present
- if (spellProcEvent->spellFamilyMask)
- {
- if (!(spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags))
- return false;
- hasFamilyMask = true;
- // Some spells are not considered as active even with spellfamilyflags set
- if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL))
- active = true;
- }
- }
- }
-
- if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY))
- {
- if (!hasFamilyMask)
- return false;
- }
-
- // Check for extra req (if none) and hit/crit
- if (procEvent_procEx == PROC_EX_NONE)
- {
- // No extra req, so can trigger only for hit/crit - spell has to be active
- if ((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active)
- return true;
- }
- else // Passive spells hits here only if resist/reflect/immune/evade
- {
- if (procExtra & AURA_SPELL_PROC_EX_MASK)
- {
- // if spell marked as procing only from not active spells
- if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL)
- return false;
- // if spell marked as procing only from active spells
- if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)
- return false;
- // Exist req for PROC_EX_EX_TRIGGER_ALWAYS
- if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
- return true;
- // PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before
- if ((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK)) == 0))
- return true;
- }
- // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
- if (procEvent_procEx & procExtra)
- return true;
- }
- return false;
-}
-
SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
{
SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId);
@@ -984,10 +820,37 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
return false;
+ // check power requirement
+ if (procEntry.AttributesMask & PROC_ATTR_REQ_POWER_COST)
+ {
+ if (!eventInfo.GetProcSpell())
+ return false;
+
+ std::vector<SpellPowerCost> const& costs = eventInfo.GetProcSpell()->GetPowerCost();
+ auto m = std::find_if(costs.begin(), costs.end(), [](SpellPowerCost const& cost) { return cost.Amount > 0; });
+ if (m == costs.end())
+ return false;
+ }
+
// always trigger for these types
if (eventInfo.GetTypeMask() & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
return true;
+ // do triggered cast checks
+ if (!(procEntry.AttributesMask & PROC_ATTR_TRIGGERED_CAN_PROC))
+ {
+ if (Spell const* spell = eventInfo.GetProcSpell())
+ {
+ if (spell->IsTriggered())
+ {
+ SpellInfo const* spellInfo = spell->GetSpellInfo();
+ if (!spellInfo->HasAttribute(SPELL_ATTR3_TRIGGERED_CAN_TRIGGER_PROC_2) &&
+ !spellInfo->HasAttribute(SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC))
+ return false;
+ }
+ }
+ }
+
// check school mask (if set) for other trigger types
if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask))
return false;
@@ -1790,226 +1653,283 @@ void SpellMgr::LoadSpellGroupStackRules()
TC_LOG_INFO("server.loading", ">> Loaded %u spell group stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
-void SpellMgr::LoadSpellProcEvents()
-{
- uint32 oldMSTime = getMSTime();
+// Used for prepare can/can't triggr aura
+static bool InitTriggerAuraData();
+// Define can trigger auras
+static bool isTriggerAura[TOTAL_AURAS];
+// Triggered always, even from triggered spells
+static bool isAlwaysTriggeredAura[TOTAL_AURAS];
+// Prepare lists
+static bool procPrepared = InitTriggerAuraData();
- mSpellProcEventMap.clear(); // need for reload case
-
- // 0 1 2 3 4 5 6 7 8 9 10 11
- QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, SpellFamilyMask3, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
- if (!result)
+// List of auras that CAN be trigger but may not exist in spell_proc_event
+// in most case need for drop charges
+// in some types of aura need do additional check
+// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic
+bool InitTriggerAuraData()
+{
+ for (uint16 i = 0; i < TOTAL_AURAS; ++i)
{
- TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty.");
- return;
+ isTriggerAura[i] = false;
+ isAlwaysTriggeredAura[i] = false;
}
+ isTriggerAura[SPELL_AURA_DUMMY] = true;
+ isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true;
+ isTriggerAura[SPELL_AURA_MOD_THREAT] = true;
+ isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
+ isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
+ isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
+ isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
+ isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
+ isTriggerAura[SPELL_AURA_TRANSFORM] = true;
+ isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
+ isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
+ isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
+ isTriggerAura[SPELL_AURA_SCHOOL_ABSORB] = true; // Savage Defense untested
+ isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
+ isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
+ isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
+ isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
+ isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
+ isTriggerAura[SPELL_AURA_MOD_POWER_REGEN_PERCENT] = true;
+ isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
+ isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
+ isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true;
+ isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true;
+ isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
+ isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE_3] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
+ isTriggerAura[SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER] = true;
+ isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
+ isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
+ isTriggerAura[SPELL_AURA_MOD_ROOT_2] = true;
+
+ isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_SPELL_MAGNET] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_SCHOOL_ABSORB] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT_2] = true;
- uint32 count = 0;
+ return true;
+}
- do
- {
- Field* fields = result->Fetch();
+void SpellMgr::LoadSpellProcs()
+{
+ uint32 oldMSTime = getMSTime();
- int32 spellId = fields[0].GetInt32();
+ mSpellProcMap.clear(); // need for reload case
- bool allRanks = false;
- if (spellId < 0)
- {
- allRanks = true;
- spellId = -spellId;
- }
+ // 0 1 2 3 4 5 6
+ QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, SpellFamilyMask3, "
+ // 7 8 9 10 11 12 13 14 15
+ "ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
- SpellInfo const* spellInfo = GetSpellInfo(spellId);
- if (!spellInfo)
+ uint32 count = 0;
+ if (result)
+ {
+ do
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` does not exist.", spellId);
- continue;
- }
+ Field* fields = result->Fetch();
- if (allRanks)
- {
- if (!spellInfo->IsRanked())
- TC_LOG_ERROR("sql.sql", "The spell %u is listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId);
+ int32 spellId = fields[0].GetInt32();
- if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
+ bool allRanks = false;
+ if (spellId < 0)
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` is not first rank of spell.", spellId);
- continue;
+ allRanks = true;
+ spellId = -spellId;
}
- }
-
- SpellProcEventEntry spellProcEvent;
- spellProcEvent.schoolMask = fields[1].GetInt8();
- spellProcEvent.spellFamilyName = fields[2].GetUInt16();
- spellProcEvent.spellFamilyMask[0] = fields[3].GetUInt32();
- spellProcEvent.spellFamilyMask[1] = fields[4].GetUInt32();
- spellProcEvent.spellFamilyMask[2] = fields[5].GetUInt32();
- spellProcEvent.spellFamilyMask[3] = fields[6].GetUInt32();
- spellProcEvent.procFlags = fields[7].GetUInt32();
- spellProcEvent.procEx = fields[8].GetUInt32();
- spellProcEvent.ppmRate = fields[9].GetFloat();
- spellProcEvent.customChance = fields[10].GetFloat();
- spellProcEvent.cooldown = fields[11].GetUInt32();
-
- while (spellInfo)
- {
- if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end())
+ SpellInfo const* spellInfo = GetSpellInfo(spellId);
+ if (!spellInfo)
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id);
- break;
+ TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` does not exist", spellId);
+ continue;
}
- if (!spellInfo->ProcFlags && !spellProcEvent.procFlags)
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` is probably not a triggered spell.", spellInfo->Id);
+ if (allRanks)
+ {
+ if (!spellInfo->IsRanked())
+ TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
- mSpellProcEventMap[spellInfo->Id] = spellProcEvent;
+ if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
+ {
+ TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` is not the first rank of the spell.", spellId);
+ continue;
+ }
+ }
- if (allRanks)
- spellInfo = spellInfo->GetNextRankSpell();
- else
- break;
- }
+ SpellProcEntry baseProcEntry;
+
+ baseProcEntry.SchoolMask = fields[1].GetInt8();
+ baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
+ baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
+ baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
+ baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
+ baseProcEntry.SpellFamilyMask[3] = fields[6].GetUInt32();
+ baseProcEntry.ProcFlags = fields[7].GetUInt32();
+ baseProcEntry.SpellTypeMask = fields[8].GetUInt32();
+ baseProcEntry.SpellPhaseMask = fields[9].GetUInt32();
+ baseProcEntry.HitMask = fields[10].GetUInt32();
+ baseProcEntry.AttributesMask = fields[11].GetUInt32();
+ baseProcEntry.ProcsPerMinute = fields[12].GetFloat();
+ baseProcEntry.Chance = fields[13].GetFloat();
+ baseProcEntry.Cooldown = Milliseconds(fields[14].GetUInt32());
+ baseProcEntry.Charges = fields[15].GetUInt8();
+
+ while (spellInfo)
+ {
+ if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
+ {
+ TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
+ break;
+ }
- ++count;
+ SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
+
+ // take defaults from dbcs
+ if (!procEntry.ProcFlags)
+ procEntry.ProcFlags = spellInfo->ProcFlags;
+ if (!procEntry.Charges)
+ procEntry.Charges = spellInfo->ProcCharges;
+ if (!procEntry.Chance && !procEntry.ProcsPerMinute)
+ procEntry.Chance = float(spellInfo->ProcChance);
+
+ // validate data
+ if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SchoolMask` set: %u", spellInfo->Id, procEntry.SchoolMask);
+ if (procEntry.SpellFamilyName && !DB2Manager::IsValidSpellFamiliyName(SpellFamilyNames(procEntry.SpellFamilyName)))
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellFamilyName` set: %u", spellInfo->Id, procEntry.SpellFamilyName);
+ if (procEntry.Chance < 0)
+ {
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `Chance` field", spellInfo->Id);
+ procEntry.Chance = 0;
+ }
+ if (procEntry.ProcsPerMinute < 0)
+ {
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ProcsPerMinute` field", spellInfo->Id);
+ procEntry.ProcsPerMinute = 0;
+ }
+ if (!procEntry.ProcFlags)
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `ProcFlags` value defined, proc will not be triggered.", spellInfo->Id);
+ if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
+ TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellTypeMask` set: %u", spellInfo->Id, procEntry.SpellTypeMask);
+ if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `SpellTypeMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
+ if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `SpellPhaseMask` value defined, but it is required for the defined `ProcFlags` value. Proc will not be triggered.", spellInfo->Id);
+ if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `SpellPhaseMask` set: %u", spellInfo->Id, procEntry.SpellPhaseMask);
+ if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `SpellPhaseMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
+ if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `HitMask` set: %u", spellInfo->Id, procEntry.HitMask);
+ if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
+ TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id);
+
+ mSpellProcMap[spellInfo->Id] = procEntry;
+
+ if (allRanks)
+ spellInfo = spellInfo->GetNextRankSpell();
+ else
+ break;
+ }
+ ++count;
+ } while (result->NextRow());
}
- while (result->NextRow());
+ else
+ TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
- TC_LOG_INFO("server.loading", ">> Loaded %u extra spell proc event conditions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-}
+ TC_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-void SpellMgr::LoadSpellProcs()
-{
- uint32 oldMSTime = getMSTime();
+ // This generates default procs to retain compatibility with previous proc system
+ TC_LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
+ count = 0;
+ oldMSTime = getMSTime();
- mSpellProcMap.clear(); // need for reload case
+ for (SpellInfo const* spellInfo : mSpellInfoMap)
+ {
+ if (!spellInfo)
+ continue;
- // 0 1 2 3 4 5 6
- QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, SpellFamilyMask3, "
- // 7 8 9 10 11 12 13 14 15
- "ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
+ if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
+ continue;
- if (!result)
- {
- TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
- return;
- }
+ bool found = false, addTriggerFlag = false;
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ {
+ if (!effect || !effect->IsEffect())
+ continue;
- uint32 count = 0;
- do
- {
- Field* fields = result->Fetch();
+ uint32 auraName = effect->ApplyAuraName;
+ if (!auraName)
+ continue;
- int32 spellId = fields[0].GetInt32();
+ if (!isTriggerAura[auraName])
+ continue;
- bool allRanks = false;
- if (spellId < 0)
- {
- allRanks = true;
- spellId = -spellId;
- }
+ found = true;
- SpellInfo const* spellInfo = GetSpellInfo(spellId);
- if (!spellInfo)
- {
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` does not exist", spellId);
- continue;
+ if (!addTriggerFlag && isAlwaysTriggeredAura[auraName])
+ addTriggerFlag = true;
+ break;
}
- if (allRanks)
- {
- if (!spellInfo->IsRanked())
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
+ if (!found)
+ continue;
- if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
- {
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` is not the first rank of the spell.", spellId);
- continue;
- }
- }
+ if (!spellInfo->ProcFlags)
+ continue;
- SpellProcEntry baseProcEntry;
+ SpellProcEntry procEntry;
+ procEntry.SchoolMask = 0;
+ procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
+ procEntry.ProcFlags = spellInfo->ProcFlags;
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ if (effect && effect->IsEffect() && isTriggerAura[effect->ApplyAuraName])
+ procEntry.SpellFamilyMask |= effect->SpellClassMask;
- baseProcEntry.SchoolMask = fields[1].GetInt8();
- baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
- baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
- baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
- baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
- baseProcEntry.SpellFamilyMask[3] = fields[6].GetUInt32();
- baseProcEntry.ProcFlags = fields[7].GetUInt32();
- baseProcEntry.SpellTypeMask = fields[8].GetUInt32();
- baseProcEntry.SpellPhaseMask = fields[9].GetUInt32();
- baseProcEntry.HitMask = fields[10].GetUInt32();
- baseProcEntry.AttributesMask = fields[11].GetUInt32();
- baseProcEntry.ProcsPerMinute = fields[12].GetFloat();
- baseProcEntry.Chance = fields[13].GetFloat();
- baseProcEntry.Cooldown = Milliseconds(fields[14].GetUInt32());
- baseProcEntry.Charges = fields[15].GetUInt8();
+ procEntry.SpellTypeMask = PROC_SPELL_TYPE_MASK_ALL;
+ procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT;
+ procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
- while (spellInfo)
+ // Reflect auras should only proc off reflects
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
{
- if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
+ if (effect && (effect->IsAura(SPELL_AURA_REFLECT_SPELLS) || effect->IsAura(SPELL_AURA_REFLECT_SPELLS_SCHOOL)))
{
- TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
+ procEntry.HitMask = PROC_HIT_REFLECT;
break;
}
+ }
- SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
-
- // take defaults from dbcs
- if (!procEntry.ProcFlags)
- procEntry.ProcFlags = spellInfo->ProcFlags;
- if (!procEntry.Charges)
- procEntry.Charges = spellInfo->ProcCharges;
- if (!procEntry.Chance && !procEntry.ProcsPerMinute)
- procEntry.Chance = float(spellInfo->ProcChance);
-
- // validate data
- if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SchoolMask` set: %u", spellInfo->Id, procEntry.SchoolMask);
- if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < 3 || procEntry.SpellFamilyName > 17 || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellFamilyName` set: %u", spellInfo->Id, procEntry.SpellFamilyName);
- if (procEntry.Chance < 0)
- {
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `Chance` field", spellInfo->Id);
- procEntry.Chance = 0;
- }
- if (procEntry.ProcsPerMinute < 0)
- {
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ProcsPerMinute` field", spellInfo->Id);
- procEntry.ProcsPerMinute = 0;
- }
- if (procEntry.Chance == 0 && procEntry.ProcsPerMinute == 0)
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have any `Chance` and `ProcsPerMinute` values defined, proc will not be triggered", spellInfo->Id);
- if (!procEntry.ProcFlags)
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `ProcFlags` value defined, proc will not be triggered.", spellInfo->Id);
- if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
- TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `SpellTypeMask` set: %u", spellInfo->Id, procEntry.SpellTypeMask);
- if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `SpellTypeMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
- if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `SpellPhaseMask` value defined, but it is required for the defined `ProcFlags` value. Proc will not be triggered.", spellInfo->Id);
- if (procEntry.SpellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL)
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `SpellPhaseMask` set: %u", spellInfo->Id, procEntry.SpellPhaseMask);
- if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `SpellPhaseMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
- if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `HitMask` set: %u", spellInfo->Id, procEntry.HitMask);
- if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
- TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id);
-
- mSpellProcMap[spellInfo->Id] = procEntry;
+ procEntry.AttributesMask = 0;
+ if (spellInfo->ProcFlags & PROC_FLAG_KILL)
+ procEntry.AttributesMask |= PROC_ATTR_REQ_EXP_OR_HONOR;
+ if (addTriggerFlag)
+ procEntry.AttributesMask |= PROC_ATTR_TRIGGERED_CAN_PROC;
- if (allRanks)
- spellInfo = spellInfo->GetNextRankSpell();
- else
- break;
- }
+ procEntry.ProcsPerMinute = 0;
+ procEntry.Chance = spellInfo->ProcChance;
+ procEntry.Cooldown = Milliseconds::zero();
+ procEntry.Charges = spellInfo->ProcCharges;
+
+ mSpellProcMap[spellInfo->Id] = procEntry;
++count;
}
- while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Generated spell proc data for %u spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void SpellMgr::LoadSpellThreats()
@@ -3105,30 +3025,12 @@ void SpellMgr::LoadSpellInfoCorrections()
const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TriggerSpell = 33760;
});
- ApplySpellFix({
- 17941, // Shadow Trance
- 22008, // Netherwind Focus
- 34477, // Misdirection
- 48108, // Hot Streak
- 51124, // Killing Machine
- 64823 // Item - Druid T8 Balance 4P Bonus
- }, [](SpellInfo* spellInfo)
- {
- spellInfo->ProcCharges = 1;
- });
-
// Fingers of Frost
ApplySpellFix({ 44544 }, [](SpellInfo* spellInfo)
{
const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->SpellClassMask = flag128(685904631, 1151048, 0, 0);
});
- // Ascendance (Talisman of Ascendance trinket)
- ApplySpellFix({ 28200 }, [](SpellInfo* spellInfo)
- {
- spellInfo->ProcCharges = 6;
- });
-
// Oscillation Field
ApplySpellFix({ 37408 }, [](SpellInfo* spellInfo)
{
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index c3d493357c1..6110e8da79c 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -213,43 +213,6 @@ enum ProcFlags
PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \
PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS)
-enum ProcFlagsExLegacy
-{
- PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag)
- PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells)
- PROC_EX_CRITICAL_HIT = 0x0000002,
- PROC_EX_MISS = 0x0000004,
- PROC_EX_RESIST = 0x0000008,
- PROC_EX_DODGE = 0x0000010,
- PROC_EX_PARRY = 0x0000020,
- PROC_EX_BLOCK = 0x0000040,
- PROC_EX_EVADE = 0x0000080,
- PROC_EX_IMMUNE = 0x0000100,
- PROC_EX_DEFLECT = 0x0000200,
- PROC_EX_ABSORB = 0x0000400,
- PROC_EX_REFLECT = 0x0000800,
- PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used)
- PROC_EX_FULL_BLOCK = 0x0002000, // block al attack damage
- PROC_EX_RESERVED2 = 0x0004000,
- PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc
- PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result
- PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet)
- PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc
-
- // Flags for internal use - do not use these in db!
- PROC_EX_INTERNAL_CANT_PROC = 0x0800000,
- PROC_EX_INTERNAL_DOT = 0x1000000,
- PROC_EX_INTERNAL_HOT = 0x2000000,
- PROC_EX_INTERNAL_TRIGGERED = 0x4000000,
- PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000
-};
-
-#define AURA_SPELL_PROC_EX_MASK \
- (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT | PROC_EX_MISS | \
- PROC_EX_RESIST | PROC_EX_DODGE | PROC_EX_PARRY | PROC_EX_BLOCK | \
- PROC_EX_EVADE | PROC_EX_IMMUNE | PROC_EX_DEFLECT | \
- PROC_EX_ABSORB | PROC_EX_REFLECT | PROC_EX_INTERRUPT)
-
enum ProcFlagsSpellType
{
PROC_SPELL_TYPE_NONE = 0x0000000,
@@ -290,23 +253,12 @@ enum ProcFlagsHit
enum ProcAttributes
{
- PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000010
+ PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000001, // requires proc target to give exp or honor for aura proc
+ PROC_ATTR_TRIGGERED_CAN_PROC = 0x0000002, // aura can proc even with triggered spells
+ PROC_ATTR_REQ_POWER_COST = 0x0000004, // requires triggering spell to have a power cost for aura proc
+ PROC_ATTR_REQ_SPELLMOD = 0x0000008 // requires triggering spell to be affected by proccing aura to drop charges
};
-struct SpellProcEventEntry
-{
- uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2
- uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value
- flag128 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
- uint32 procFlags; // bitmask for matching proc event
- uint32 procEx; // proc Extend info (see ProcFlagsEx)
- float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc
- float customChance; // Owerride chance (in most cases for debug only)
- uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_
-};
-
-typedef std::unordered_map<uint32, SpellProcEventEntry> SpellProcEventMap;
-
struct SpellProcEntry
{
uint32 SchoolMask; // if nonzero - bitmask for matching proc condition based on spell's school
@@ -691,10 +643,6 @@ class TC_GAME_API SpellMgr
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const;
- // Spell proc event table
- SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
- bool IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const;
-
// Spell proc table
SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const;
bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
@@ -751,7 +699,6 @@ class TC_GAME_API SpellMgr
void LoadSpellTargetPositions();
void LoadSpellGroups();
void LoadSpellGroupStackRules();
- void LoadSpellProcEvents();
void LoadSpellProcs();
void LoadSpellThreats();
void LoadSkillLineAbilityMap();
@@ -779,7 +726,6 @@ class TC_GAME_API SpellMgr
SpellSpellGroupMap mSpellSpellGroup;
SpellGroupSpellMap mSpellGroupSpell;
SpellGroupStackMap mSpellGroupStack;
- SpellProcEventMap mSpellProcEventMap;
SpellProcMap mSpellProcMap;
SpellThreatMap mSpellThreatMap;
SpellPetAuraMap mSpellPetAuraMap;
diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp
index c96086f89ce..d4f7eb2b357 100644
--- a/src/server/game/Spells/SpellScript.cpp
+++ b/src/server/game/Spells/SpellScript.cpp
@@ -769,6 +769,10 @@ bool AuraScript::_Validate(SpellInfo const* entry)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
+ for (auto itr = DoCheckEffectProc.begin(); itr != DoCheckEffectProc.end(); ++itr)
+ if (!itr->GetAffectedEffectsMask(entry))
+ TC_LOG_ERROR("scripts", "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `DoCheckEffectProc` of AuraScript won't be executed", entry->Id, itr->ToString().c_str(), m_scriptName->c_str());
+
for (auto itr = DoPrepareProc.begin(); itr != DoPrepareProc.end(); ++itr)
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
TC_LOG_ERROR("scripts", "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `DoPrepareProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
@@ -936,6 +940,17 @@ bool AuraScript::CheckProcHandler::Call(AuraScript* auraScript, ProcEventInfo& e
return (auraScript->*_HandlerScript)(eventInfo);
}
+AuraScript::CheckEffectProcHandler::CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName)
+ : AuraScript::EffectBase(effIndex, effName)
+{
+ _HandlerScript = handlerScript;
+}
+
+bool AuraScript::CheckEffectProcHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+{
+ return (auraScript->*_HandlerScript)(aurEff, eventInfo);
+}
+
AuraScript::AuraProcHandler::AuraProcHandler(AuraProcFnType handlerScript)
{
_HandlerScript = handlerScript;
@@ -1197,6 +1212,7 @@ Unit* AuraScript::GetTarget() const
case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD:
case AURA_SCRIPT_HOOK_EFFECT_SPLIT:
case AURA_SCRIPT_HOOK_CHECK_PROC:
+ case AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC:
case AURA_SCRIPT_HOOK_PREPARE_PROC:
case AURA_SCRIPT_HOOK_PROC:
case AURA_SCRIPT_HOOK_AFTER_PROC:
diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h
index ee1a058f543..268ef5cc12e 100644
--- a/src/server/game/Spells/SpellScript.h
+++ b/src/server/game/Spells/SpellScript.h
@@ -506,6 +506,7 @@ enum AuraScriptHookType
AURA_SCRIPT_HOOK_AFTER_DISPEL,
// Spell Proc Hooks
AURA_SCRIPT_HOOK_CHECK_PROC,
+ AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC,
AURA_SCRIPT_HOOK_PREPARE_PROC,
AURA_SCRIPT_HOOK_PROC,
AURA_SCRIPT_HOOK_EFFECT_PROC,
@@ -537,6 +538,7 @@ class TC_GAME_API AuraScript : public _SpellScript
typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect*, DamageInfo &, uint32 &); \
typedef void(CLASSNAME::*AuraEffectSplitFnType)(AuraEffect*, DamageInfo &, uint32 &); \
typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \
+ typedef bool(CLASSNAME::*AuraCheckEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
typedef void(CLASSNAME::*AuraProcFnType)(ProcEventInfo&); \
typedef void(CLASSNAME::*AuraEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \
@@ -646,6 +648,14 @@ class TC_GAME_API AuraScript : public _SpellScript
private:
AuraCheckProcFnType _HandlerScript;
};
+ class TC_GAME_API CheckEffectProcHandler : public EffectBase
+ {
+ public:
+ CheckEffectProcHandler(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName);
+ bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo);
+ private:
+ AuraCheckEffectProcFnType _HandlerScript;
+ };
class TC_GAME_API AuraProcHandler
{
public:
@@ -676,6 +686,7 @@ class TC_GAME_API AuraScript : public _SpellScript
class EffectManaShieldFunction : public AuraScript::EffectManaShieldHandler { public: EffectManaShieldFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectManaShieldHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) { } }; \
class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) { } }; \
class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) { } }; \
+ class CheckEffectProcHandlerFunction : public AuraScript::CheckEffectProcHandler { public: CheckEffectProcHandlerFunction(AuraCheckEffectProcFnType handlerScript, uint8 effIndex, uint16 effName) : AuraScript::CheckEffectProcHandler((AuraScript::AuraCheckEffectProcFnType)handlerScript, effIndex, effName) { } }; \
class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) { } }; \
class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) { } }
@@ -814,6 +825,12 @@ class TC_GAME_API AuraScript : public _SpellScript
HookList<CheckProcHandler> DoCheckProc;
#define AuraCheckProcFn(F) CheckProcHandlerFunction(&F)
+ // executed when aura effect checks if it can proc the aura
+ // example: DoCheckEffectProc += AuraCheckEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier);
+ // where function is bool function (AuraEffect const* aurEff, ProcEventInfo& eventInfo);
+ HookList<CheckEffectProcHandler> DoCheckEffectProc;
+ #define AuraCheckEffectProcFn(F, I, N) CheckEffectProcHandlerFunction(&F, I, N)
+
// executed before aura procs (possibility to prevent charge drop/cooldown)
// example: DoPrepareProc += AuraProcFn(class::function);
// where function is: void function (ProcEventInfo& eventInfo);
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 2692e0bbcff..f8eb1a019f4 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1668,9 +1668,6 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Spell Learn Spells...");
sSpellMgr->LoadSpellLearnSpells();
- TC_LOG_INFO("server.loading", "Loading Spell Proc Event conditions...");
- sSpellMgr->LoadSpellProcEvents();
-
TC_LOG_INFO("server.loading", "Loading Spell Proc conditions and data...");
sSpellMgr->LoadSpellProcs();
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index fa494b6d709..b657e9e56fe 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -149,7 +149,6 @@ public:
{ "spell_loot_template", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE, true, &HandleReloadLootTemplatesSpellCommand, "" },
{ "spell_linked_spell", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL, true, &HandleReloadSpellLinkedSpellCommand, "" },
{ "spell_pet_auras", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS, true, &HandleReloadSpellPetAurasCommand, "" },
- { "spell_proc_event", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC_EVENT, true, &HandleReloadSpellProcEventCommand, "" },
{ "spell_proc", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC, true, &HandleReloadSpellProcsCommand, "" },
{ "spell_scripts", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS, true, &HandleReloadSpellScriptsCommand, "" },
{ "spell_target_position", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION, true, &HandleReloadSpellTargetPositionCommand, "" },
@@ -289,7 +288,6 @@ public:
HandleReloadSpellGroupsCommand(handler, "a");
HandleReloadSpellLearnSpellCommand(handler, "a");
HandleReloadSpellLinkedSpellCommand(handler, "a");
- HandleReloadSpellProcEventCommand(handler, "a");
HandleReloadSpellProcsCommand(handler, "a");
HandleReloadSpellTargetPositionCommand(handler, "a");
HandleReloadSpellThreatsCommand(handler, "a");
@@ -830,14 +828,6 @@ public:
return true;
}
- static bool HandleReloadSpellProcEventCommand(ChatHandler* handler, const char* /*args*/)
- {
- TC_LOG_INFO("misc", "Re-Loading Spell Proc Event conditions...");
- sSpellMgr->LoadSpellProcEvents();
- handler->SendGlobalGMSysMessage("DB table `spell_proc_event` (spell proc trigger requirements) reloaded.");
- return true;
- }
-
static bool HandleReloadSpellProcsCommand(ChatHandler* handler, const char* /*args*/)
{
TC_LOG_INFO("misc", "Re-Loading Spell Proc conditions and data...");
diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp
index e28bd4a8236..362d477be7e 100644
--- a/src/server/scripts/Spells/spell_druid.cpp
+++ b/src/server/scripts/Spells/spell_druid.cpp
@@ -24,6 +24,7 @@
#include "ScriptMgr.h"
#include "Containers.h"
#include "Player.h"
+#include "Spell.h"
#include "SpellAuraEffects.h"
#include "SpellHistory.h"
#include "SpellMgr.h"
@@ -908,12 +909,12 @@ class spell_dru_t3_8p_bonus : public SpellScriptLoader
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
- if (!spellInfo)
+ Spell const* spell = eventInfo.GetProcSpell();
+ if (!spell)
return;
Unit* caster = eventInfo.GetActor();
- std::vector<SpellPowerCost> costs = spellInfo->CalcPowerCost(caster, spellInfo->GetSchoolMask());
+ std::vector<SpellPowerCost> const& costs = spell->GetPowerCost();
auto m = std::find_if(costs.begin(), costs.end(), [](SpellPowerCost const& cost) { return cost.Power == POWER_MANA; });
if (m == costs.end())
return;
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 1c229714dd5..018e527dc90 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -32,6 +32,7 @@
#include "Player.h"
#include "ScriptedCreature.h"
#include "SkillDiscovery.h"
+#include "Spell.h"
#include "SpellAuraEffects.h"
#include "SpellHistory.h"
#include "SpellMgr.h"
@@ -1546,9 +1547,9 @@ class spell_item_pendant_of_the_violet_eye : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
+ if (Spell const* spell = eventInfo.GetProcSpell())
{
- std::vector<SpellPowerCost> costs = spellInfo->CalcPowerCost(GetTarget(), spellInfo->GetSchoolMask());
+ std::vector<SpellPowerCost> const& costs = spell->GetPowerCost();
auto m = std::find_if(costs.begin(), costs.end(), [](SpellPowerCost const& cost) { return cost.Power == POWER_MANA && cost.Amount > 0; });
if (m != costs.end())
return true;
diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp
index ec456e2c42f..f4efe94d241 100644
--- a/src/server/scripts/Spells/spell_mage.cpp
+++ b/src/server/scripts/Spells/spell_mage.cpp
@@ -598,14 +598,14 @@ class spell_mage_master_of_elements : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return eventInfo.GetDamageInfo()->GetSpellInfo() != nullptr;
+ return eventInfo.GetProcSpell() != nullptr;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- std::vector<SpellPowerCost> costs = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask());
+ std::vector<SpellPowerCost> const& costs = eventInfo.GetProcSpell()->GetPowerCost();
auto m = std::find_if(costs.begin(), costs.end(), [](SpellPowerCost const& cost) { return cost.Power == POWER_MANA; });
if (m != costs.end())
{
diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp
index 5298c2bef57..bcce99a8dae 100644
--- a/src/server/scripts/Spells/spell_shaman.cpp
+++ b/src/server/scripts/Spells/spell_shaman.cpp
@@ -649,17 +649,14 @@ class spell_sha_item_mana_surge : public SpellScriptLoader
bool CheckProc(ProcEventInfo& eventInfo)
{
- return eventInfo.GetSpellInfo() != nullptr;
+ return eventInfo.GetProcSpell() != nullptr;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
- SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
- if (!spellInfo)
- return;
- std::vector<SpellPowerCost> costs = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask());
+ std::vector<SpellPowerCost> const& costs = eventInfo.GetProcSpell()->GetPowerCost();
auto m = std::find_if(costs.begin(), costs.end(), [](SpellPowerCost const& cost) { return cost.Power == POWER_MANA; });
if (m != costs.end())
{