aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells/SpellMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Spells/SpellMgr.cpp')
-rw-r--r--src/server/game/Spells/SpellMgr.cpp570
1 files changed, 337 insertions, 233 deletions
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index c00b07a157f..1e2bc42c17d 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -32,6 +32,36 @@
#include "SpellAuraDefines.h"
#include "SpellInfo.h"
#include <G3D/g3dmath.h>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/composite_key.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/member.hpp>
+
+namespace
+{
+ struct SpellIdDifficultyIndex;
+ struct SpellIdIndex;
+
+ boost::multi_index::multi_index_container<
+ SpellInfo,
+ boost::multi_index::indexed_by<
+ boost::multi_index::hashed_unique<
+ boost::multi_index::tag<SpellIdDifficultyIndex>,
+ boost::multi_index::composite_key<
+ SpellInfo,
+ boost::multi_index::member<SpellInfo, uint32, &SpellInfo::Id>,
+ boost::multi_index::member<SpellInfo, Difficulty, &SpellInfo::Difficulty>
+ >
+ >,
+ boost::multi_index::hashed_non_unique<
+ boost::multi_index::tag<SpellIdIndex>,
+ boost::multi_index::member<SpellInfo, uint32, &SpellInfo::Id>
+ >
+ >
+ > mSpellInfoMap;
+
+ std::unordered_map<std::pair<uint32, Difficulty>, SpellProcEntry> mSpellProcMap;
+}
PetFamilySpellsStore sPetFamilySpellsStore;
@@ -80,7 +110,7 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg
bool needCheckReagents = false;
// check effects
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfo->GetEffects())
{
if (!effect)
continue;
@@ -128,7 +158,7 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg
}
case SPELL_EFFECT_LEARN_SPELL:
{
- SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(effect->TriggerSpell);
+ SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(effect->TriggerSpell, DIFFICULTY_NONE);
if (!IsSpellValid(spellInfo2, player, msg))
{
if (msg)
@@ -425,12 +455,25 @@ SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
return SPELL_GROUP_STACK_RULE_DEFAULT;
}
-SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
+SpellProcEntry const* SpellMgr::GetSpellProcEntry(SpellInfo const* spellInfo) const
{
- SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId);
- if (itr != mSpellProcMap.end())
- return &itr->second;
- return NULL;
+ SpellProcEntry const* procEntry = Trinity::Containers::MapGetValuePtr(mSpellProcMap, { spellInfo->Id, spellInfo->Difficulty });
+ if (procEntry)
+ return procEntry;
+
+ if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(spellInfo->Difficulty))
+ {
+ do
+ {
+ procEntry = Trinity::Containers::MapGetValuePtr(mSpellProcMap, { spellInfo->Id, Difficulty(difficulty->FallbackDifficultyID) });
+ if (procEntry)
+ return procEntry;
+
+ difficulty = sDifficultyStore.LookupEntry(difficulty->FallbackDifficultyID);
+ } while (difficulty);
+ }
+
+ return nullptr;
}
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo)
@@ -619,6 +662,44 @@ SpellAreaForQuestAreaMapBounds SpellMgr::GetSpellAreaForQuestAreaMapBounds(uint3
return mSpellAreaForQuestAreaMap.equal_range(std::pair<uint32, uint32>(area_id, quest_id));
}
+SpellInfo const* SpellMgr::GetSpellInfo(uint32 spellId, Difficulty difficulty) const
+{
+ auto itr = mSpellInfoMap.find(boost::make_tuple(spellId, difficulty));
+ if (itr != mSpellInfoMap.end())
+ return &*itr;
+
+ if (DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty))
+ {
+ do
+ {
+ itr = mSpellInfoMap.find(boost::make_tuple(spellId, Difficulty(difficultyEntry->FallbackDifficultyID)));
+ if (itr != mSpellInfoMap.end())
+ return &*itr;
+
+ difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID);
+ } while (difficultyEntry);
+ }
+
+ return nullptr;
+}
+
+auto _GetSpellInfo(uint32 spellId)
+{
+ return Trinity::Containers::MakeIteratorPair(mSpellInfoMap.get<SpellIdIndex>().equal_range(spellId));
+}
+
+void SpellMgr::ForEachSpellInfo(std::function<void(SpellInfo const*)> callback)
+{
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
+ callback(&spellInfo);
+}
+
+void SpellMgr::ForEachSpellInfoDifficulty(uint32 spellId, std::function<void(SpellInfo const*)> callback)
+{
+ for (SpellInfo const& spellInfo : _GetSpellInfo(spellId))
+ callback(&spellInfo);
+}
+
bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const
{
if (gender != GENDER_NONE) // is not expected gender
@@ -712,7 +793,8 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
void SpellMgr::UnloadSpellInfoChains()
{
for (SpellChainMap::iterator itr = mSpellChains.begin(); itr != mSpellChains.end(); ++itr)
- mSpellInfoMap[itr->first]->ChainEntry = NULL;
+ for (SpellInfo const& spellInfo : _GetSpellInfo(itr->first))
+ const_cast<SpellInfo&>(spellInfo).ChainEntry = NULL;
mSpellChains.clear();
}
@@ -728,7 +810,7 @@ void SpellMgr::LoadSpellRanks()
if (!skillAbility->SupercedesSpell)
continue;
- if (!GetSpellInfo(skillAbility->SupercedesSpell) || !GetSpellInfo(skillAbility->Spell))
+ if (!GetSpellInfo(skillAbility->SupercedesSpell, DIFFICULTY_NONE) || !GetSpellInfo(skillAbility->Spell, DIFFICULTY_NONE))
continue;
chains[skillAbility->SupercedesSpell] = skillAbility->Spell;
@@ -741,29 +823,31 @@ void SpellMgr::LoadSpellRanks()
if (hasPrev.count(itr->first))
continue;
- SpellInfo const* first = AssertSpellInfo(itr->first);
- SpellInfo const* next = AssertSpellInfo(itr->second);
+ SpellInfo const* first = AssertSpellInfo(itr->first, DIFFICULTY_NONE);
+ SpellInfo const* next = AssertSpellInfo(itr->second, DIFFICULTY_NONE);
mSpellChains[itr->first].first = first;
mSpellChains[itr->first].prev = nullptr;
mSpellChains[itr->first].next = next;
mSpellChains[itr->first].last = next;
mSpellChains[itr->first].rank = 1;
- mSpellInfoMap[itr->first]->ChainEntry = &mSpellChains[itr->first];
+ for (SpellInfo const& difficultyInfo : _GetSpellInfo(itr->first))
+ const_cast<SpellInfo&>(difficultyInfo).ChainEntry = &mSpellChains[itr->first];
mSpellChains[itr->second].first = first;
mSpellChains[itr->second].prev = first;
mSpellChains[itr->second].next = nullptr;
mSpellChains[itr->second].last = next;
mSpellChains[itr->second].rank = 2;
- mSpellInfoMap[itr->second]->ChainEntry = &mSpellChains[itr->second];
+ for (SpellInfo const& difficultyInfo : _GetSpellInfo(itr->second))
+ const_cast<SpellInfo&>(difficultyInfo).ChainEntry = &mSpellChains[itr->second];
uint8 rank = 3;
auto nextItr = chains.find(itr->second);
while (nextItr != chains.end())
{
- SpellInfo const* prev = AssertSpellInfo(nextItr->first); // already checked in previous iteration (or above, in case this is the first one)
- SpellInfo const* last = AssertSpellInfo(nextItr->second);
+ SpellInfo const* prev = AssertSpellInfo(nextItr->first, DIFFICULTY_NONE); // already checked in previous iteration (or above, in case this is the first one)
+ SpellInfo const* last = AssertSpellInfo(nextItr->second, DIFFICULTY_NONE);
mSpellChains[nextItr->first].next = last;
@@ -772,7 +856,8 @@ void SpellMgr::LoadSpellRanks()
mSpellChains[nextItr->second].next = nullptr;
mSpellChains[nextItr->second].last = last;
mSpellChains[nextItr->second].rank = rank++;
- mSpellInfoMap[nextItr->second]->ChainEntry = &mSpellChains[nextItr->second];
+ for (SpellInfo const& difficultyInfo : _GetSpellInfo(nextItr->second))
+ const_cast<SpellInfo&>(difficultyInfo).ChainEntry = &mSpellChains[nextItr->second];
// fill 'last'
do
@@ -814,14 +899,14 @@ void SpellMgr::LoadSpellRequired()
uint32 spell_req = fields[1].GetUInt32();
// check if chain is made with valid first spell
- SpellInfo const* spell = GetSpellInfo(spell_id);
+ SpellInfo const* spell = GetSpellInfo(spell_id, DIFFICULTY_NONE);
if (!spell)
{
TC_LOG_ERROR("sql.sql", "spell_id %u in `spell_required` table could not be found in dbc, skipped.", spell_id);
continue;
}
- SpellInfo const* reqSpell = GetSpellInfo(spell_req);
+ SpellInfo const* reqSpell = GetSpellInfo(spell_req, DIFFICULTY_NONE);
if (!reqSpell)
{
TC_LOG_ERROR("sql.sql", "req_spell %u in `spell_required` table could not be found in dbc, skipped.", spell_req);
@@ -857,12 +942,12 @@ void SpellMgr::LoadSpellLearnSkills()
// search auto-learned skills and add its to map also for use in unlearn spells/talents
uint32 dbc_count = 0;
- for (SpellInfo const* entry : mSpellInfoMap)
+ for (SpellInfo const& entry : mSpellInfoMap)
{
- if (!entry)
+ if (entry.Difficulty != DIFFICULTY_NONE)
continue;
- for (SpellEffectInfo const* effect : entry->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : entry.GetEffects())
{
if (!effect)
continue;
@@ -889,7 +974,7 @@ void SpellMgr::LoadSpellLearnSkills()
continue;
}
- mSpellLearnSkills[entry->Id] = dbc_node;
+ mSpellLearnSkills[entry.Id] = dbc_node;
++dbc_count;
break;
}
@@ -925,14 +1010,14 @@ void SpellMgr::LoadSpellLearnSpells()
node.Active = fields[2].GetBool();
node.AutoLearned = false;
- SpellInfo const* spellInfo = GetSpellInfo(spell_id);
+ SpellInfo const* spellInfo = GetSpellInfo(spell_id, DIFFICULTY_NONE);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_learn_spell` does not exist.", spell_id);
continue;
}
- if (!GetSpellInfo(node.Spell))
+ if (!GetSpellInfo(node.Spell, DIFFICULTY_NONE))
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_learn_spell` learning non-existing spell %u.", spell_id, node.Spell);
continue;
@@ -954,14 +1039,12 @@ void SpellMgr::LoadSpellLearnSpells()
// search auto-learned spells and add its to map also for use in unlearn spells/talents
uint32 dbc_count = 0;
- for (uint32 spell = 0; spell < GetSpellInfoStoreSize(); ++spell)
+ for (SpellInfo const& entry : mSpellInfoMap)
{
- SpellInfo const* entry = GetSpellInfo(spell);
-
- if (!entry)
+ if (entry.Difficulty != DIFFICULTY_NONE)
continue;
- for (SpellEffectInfo const* effect : entry->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : entry.GetEffects())
{
if (effect && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
{
@@ -971,15 +1054,15 @@ void SpellMgr::LoadSpellLearnSpells()
dbc_node.OverridesSpell = 0;
// ignore learning not existed spells (broken/outdated/or generic learnig spell 483
- if (!GetSpellInfo(dbc_node.Spell))
+ if (!GetSpellInfo(dbc_node.Spell, DIFFICULTY_NONE))
continue;
// talent or passive spells or skill-step spells auto-cast and not need dependent learning,
// pet teaching spells must not be dependent learning (cast)
// other required explicit dependent learning
- dbc_node.AutoLearned = effect->TargetA.GetTarget() == TARGET_UNIT_PET || entry->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
+ dbc_node.AutoLearned = effect->TargetA.GetTarget() == TARGET_UNIT_PET || entry.HasAttribute(SPELL_ATTR0_CU_IS_TALENT) || entry.IsPassive() || entry.HasEffect(SPELL_EFFECT_SKILL_STEP);
- SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spell);
+ SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(entry.Id);
bool found = false;
for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
@@ -987,7 +1070,7 @@ void SpellMgr::LoadSpellLearnSpells()
if (itr->second.Spell == dbc_node.Spell)
{
TC_LOG_ERROR("sql.sql", "The spell %u is an auto-learn spell %u in spell.dbc and the record in `spell_learn_spell` is redundant. Please update your DB.",
- spell, dbc_node.Spell);
+ entry.Id, dbc_node.Spell);
found = true;
break;
}
@@ -995,7 +1078,7 @@ void SpellMgr::LoadSpellLearnSpells()
if (!found) // add new spell-spell pair if not found
{
- mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell, dbc_node));
+ mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(entry.Id, dbc_node));
++dbc_count;
}
}
@@ -1004,7 +1087,7 @@ void SpellMgr::LoadSpellLearnSpells()
for (SpellLearnSpellEntry const* spellLearnSpell : sSpellLearnSpellStore)
{
- if (!GetSpellInfo(spellLearnSpell->SpellID))
+ if (!GetSpellInfo(spellLearnSpell->SpellID, DIFFICULTY_NONE))
continue;
SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spellLearnSpell->LearnSpellID);
@@ -1092,7 +1175,7 @@ void SpellMgr::LoadSpellTargetPositions()
continue;
}
- SpellInfo const* spellInfo = GetSpellInfo(spellId);
+ SpellInfo const* spellInfo = GetSpellInfo(spellId, DIFFICULTY_NONE);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "Spell (Id: %u) listed in `spell_target_position` does not exist.", spellId);
@@ -1200,7 +1283,7 @@ void SpellMgr::LoadSpellGroups()
}
else
{
- SpellInfo const* spellInfo = GetSpellInfo(itr->second);
+ SpellInfo const* spellInfo = GetSpellInfo(itr->second, DIFFICULTY_NONE);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_group` does not exist", itr->second);
@@ -1302,8 +1385,8 @@ void SpellMgr::LoadSpellGroupStackRules()
for (uint32 spellId : spellIds)
{
- SpellInfo const* spellInfo = AssertSpellInfo(spellId);
- for (SpellEffectInfo const* effectInfo : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ SpellInfo const* spellInfo = AssertSpellInfo(spellId, DIFFICULTY_NONE);
+ for (SpellEffectInfo const* effectInfo : spellInfo->GetEffects())
{
if (!effectInfo->IsAura())
continue;
@@ -1351,14 +1434,14 @@ void SpellMgr::LoadSpellGroupStackRules()
// re-check spells against guessed group
for (uint32 spellId : spellIds)
{
- SpellInfo const* spellInfo = AssertSpellInfo(spellId);
+ SpellInfo const* spellInfo = AssertSpellInfo(spellId, DIFFICULTY_NONE);
bool found = false;
while (spellInfo)
{
for (uint32 auraType : auraTypes)
{
- if (spellInfo->HasAura(DIFFICULTY_NONE, AuraType(auraType)))
+ if (spellInfo->HasAura(AuraType(auraType)))
{
found = true;
break;
@@ -1410,7 +1493,7 @@ void SpellMgr::LoadSpellProcs()
spellId = -spellId;
}
- SpellInfo const* spellInfo = GetSpellInfo(spellId);
+ SpellInfo const* spellInfo = GetSpellInfo(spellId, DIFFICULTY_NONE);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` does not exist", spellId);
@@ -1450,7 +1533,7 @@ void SpellMgr::LoadSpellProcs()
while (spellInfo)
{
- if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
+ if (mSpellProcMap.find({ spellInfo->Id, spellInfo->Difficulty }) != 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;
@@ -1500,7 +1583,7 @@ void SpellMgr::LoadSpellProcs()
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;
+ mSpellProcMap[{ spellInfo->Id, spellInfo->Difficulty }] = procEntry;
if (allRanks)
spellInfo = spellInfo->GetNextRankSpell();
@@ -1608,22 +1691,19 @@ void SpellMgr::LoadSpellProcs()
count = 0;
oldMSTime = getMSTime();
- for (SpellInfo const* spellInfo : mSpellInfoMap)
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
{
- if (!spellInfo)
- continue;
-
// Data already present in DB, overwrites default proc
- if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
+ if (mSpellProcMap.find({ spellInfo.Id, spellInfo.Difficulty }) != mSpellProcMap.end())
continue;
// Nothing to do if no flags set
- if (!spellInfo->ProcFlags)
+ if (!spellInfo.ProcFlags)
continue;
bool addTriggerFlag = false;
uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE;
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfo.GetEffects())
{
if (!effect || !effect->IsEffect())
continue;
@@ -1641,7 +1721,7 @@ void SpellMgr::LoadSpellProcs()
// many proc auras with taken procFlag mask don't have attribute "can proc with triggered"
// they should proc nevertheless (example mage armor spells with judgement)
- if (!addTriggerFlag && (spellInfo->ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0)
+ if (!addTriggerFlag && (spellInfo.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0)
{
switch (auraName)
{
@@ -1658,11 +1738,11 @@ void SpellMgr::LoadSpellProcs()
if (!procSpellTypeMask)
{
- for (SpellEffectInfo const* effectInfo : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effectInfo : spellInfo.GetEffects())
{
if (effectInfo && effectInfo->IsAura())
{
- TC_LOG_ERROR("sql.sql", "Spell Id %u has DBC ProcFlags %u, but it's of non-proc aura type, it probably needs an entry in `spell_proc` table to be handled correctly.", spellInfo->Id, spellInfo->ProcFlags);
+ TC_LOG_ERROR("sql.sql", "Spell Id %u has DBC ProcFlags %u, but it's of non-proc aura type, it probably needs an entry in `spell_proc` table to be handled correctly.", spellInfo.Id, spellInfo.ProcFlags);
break;
}
}
@@ -1672,20 +1752,20 @@ void SpellMgr::LoadSpellProcs()
SpellProcEntry procEntry;
procEntry.SchoolMask = 0;
- procEntry.ProcFlags = spellInfo->ProcFlags;
+ procEntry.ProcFlags = spellInfo.ProcFlags;
procEntry.SpellFamilyName = 0;
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfo.GetEffects())
if (effect && effect->IsEffect() && isTriggerAura[effect->ApplyAuraName])
procEntry.SpellFamilyMask |= effect->SpellClassMask;
if (procEntry.SpellFamilyMask)
- procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
+ procEntry.SpellFamilyName = spellInfo.SpellFamilyName;
procEntry.SpellTypeMask = procSpellTypeMask;
procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT;
procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfo.GetEffects())
{
if (!effect || !effect->IsAura())
continue;
@@ -1713,17 +1793,17 @@ void SpellMgr::LoadSpellProcs()
procEntry.AttributesMask = 0;
procEntry.DisableEffectsMask = 0;
- if (spellInfo->ProcFlags & PROC_FLAG_KILL)
+ if (spellInfo.ProcFlags & PROC_FLAG_KILL)
procEntry.AttributesMask |= PROC_ATTR_REQ_EXP_OR_HONOR;
if (addTriggerFlag)
procEntry.AttributesMask |= PROC_ATTR_TRIGGERED_CAN_PROC;
procEntry.ProcsPerMinute = 0;
- procEntry.Chance = spellInfo->ProcChance;
- procEntry.Cooldown = Milliseconds(spellInfo->ProcCooldown);
- procEntry.Charges = spellInfo->ProcCharges;
+ procEntry.Chance = spellInfo.ProcChance;
+ procEntry.Cooldown = Milliseconds(spellInfo.ProcCooldown);
+ procEntry.Charges = spellInfo.ProcCharges;
- mSpellProcMap[spellInfo->Id] = procEntry;
+ mSpellProcMap[{ spellInfo.Id, spellInfo.Difficulty }] = procEntry;
++count;
}
@@ -1751,7 +1831,7 @@ void SpellMgr::LoadSpellThreats()
uint32 entry = fields[0].GetUInt32();
- if (!GetSpellInfo(entry))
+ if (!GetSpellInfo(entry, DIFFICULTY_NONE))
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_threat` does not exist.", entry);
continue;
@@ -1819,7 +1899,7 @@ void SpellMgr::LoadSpellPetAuras()
itr->second.AddAura(pet, aura);
else
{
- SpellInfo const* spellInfo = GetSpellInfo(spell);
+ SpellInfo const* spellInfo = GetSpellInfo(spell, DIFFICULTY_NONE);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_pet_auras` does not exist.", spell);
@@ -1840,7 +1920,7 @@ void SpellMgr::LoadSpellPetAuras()
continue;
}
- SpellInfo const* spellInfo2 = GetSpellInfo(aura);
+ SpellInfo const* spellInfo2 = GetSpellInfo(aura, DIFFICULTY_NONE);
if (!spellInfo2)
{
TC_LOG_ERROR("sql.sql", "The aura %u listed in `spell_pet_auras` does not exist.", aura);
@@ -1866,20 +1946,16 @@ void SpellMgr::LoadEnchantCustomAttr()
mEnchantCustomAttr.resize(size);
for (uint32 i = 0; i < size; ++i)
- mEnchantCustomAttr[i] = 0;
+ mEnchantCustomAttr[i] = false;
uint32 count = 0;
- for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
{
- SpellInfo const* spellInfo = GetSpellInfo(i);
- if (!spellInfo)
- continue;
-
/// @todo find a better check
- if (!spellInfo->HasAttribute(SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT))
+ if (!spellInfo.HasAttribute(SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !spellInfo.HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT))
continue;
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfo.GetEffects())
{
if (effect && effect->Effect == SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY)
{
@@ -1963,7 +2039,7 @@ void SpellMgr::LoadSpellLinked()
int32 effect = fields[1].GetInt32();
int32 type = fields[2].GetUInt8();
- SpellInfo const* spellInfo = GetSpellInfo(abs(trigger));
+ SpellInfo const* spellInfo = GetSpellInfo(abs(trigger), DIFFICULTY_NONE);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_linked_spell` does not exist.", abs(trigger));
@@ -1971,13 +2047,13 @@ void SpellMgr::LoadSpellLinked()
}
if (effect >= 0)
- for (SpellEffectInfo const* eff : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* eff : spellInfo->GetEffects())
{
if (eff && eff->CalcValue() == abs(effect))
TC_LOG_ERROR("sql.sql", "The spell %u Effect: %u listed in `spell_linked_spell` has same bp%u like effect (possible hack)", abs(trigger), abs(effect), eff->EffectIndex);
}
- spellInfo = GetSpellInfo(abs(effect));
+ spellInfo = GetSpellInfo(abs(effect), DIFFICULTY_NONE);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_linked_spell` does not exist.", abs(effect));
@@ -2025,17 +2101,13 @@ void SpellMgr::LoadPetLevelupSpellMap()
if (!skillLine)
continue;
- //if (skillLine->skillId != creatureFamily->SkillLine[0] &&
- // (!creatureFamily->SkillLine[1] || skillLine->skillId != creatureFamily->SkillLine[1]))
- // continue;
-
if (skillLine->SkillLine != creatureFamily->SkillLine[j])
continue;
if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN)
continue;
- SpellInfo const* spell = GetSpellInfo(skillLine->Spell);
+ SpellInfo const* spell = GetSpellInfo(skillLine->Spell, DIFFICULTY_NONE);
if (!spell) // not exist or triggered or talent
continue;
@@ -2115,13 +2187,11 @@ void SpellMgr::LoadPetDefaultSpells()
oldMSTime = getMSTime();
// different summon spells
- for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
+ for (SpellInfo const& spellEntry : mSpellInfoMap)
{
- SpellInfo const* spellEntry = GetSpellInfo(i);
- if (!spellEntry)
- continue;
+ if (spellEntry.Difficulty != DIFFICULTY_NONE)
- for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellEntry.GetEffects())
{
if (effect && (effect->Effect == SPELL_EFFECT_SUMMON || effect->Effect == SPELL_EFFECT_SUMMON_PET))
{
@@ -2187,7 +2257,7 @@ void SpellMgr::LoadSpellAreas()
spellArea.gender = Gender(fields[8].GetUInt8());
spellArea.flags = fields[9].GetUInt8();
- if (SpellInfo const* spellInfo = GetSpellInfo(spell))
+ if (SpellInfo const* spellInfo = GetSpellInfo(spell, DIFFICULTY_NONE))
{
if (spellArea.flags & SPELL_AREA_FLAG_AUTOCAST)
const_cast<SpellInfo*>(spellInfo)->Attributes |= SPELL_ATTR0_CANT_CANCEL;
@@ -2251,7 +2321,7 @@ void SpellMgr::LoadSpellAreas()
if (spellArea.auraSpell)
{
- SpellInfo const* spellInfo = GetSpellInfo(abs(spellArea.auraSpell));
+ SpellInfo const* spellInfo = GetSpellInfo(abs(spellArea.auraSpell), DIFFICULTY_NONE);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has wrong aura spell (%u) requirement", spell, abs(spellArea.auraSpell));
@@ -2351,8 +2421,8 @@ void SpellMgr::LoadSpellInfoStore()
uint32 oldMSTime = getMSTime();
UnloadSpellInfoStore();
- mSpellInfoMap.resize(sSpellNameStore.GetNumRows(), NULL);
- std::unordered_map<uint32, SpellInfoLoadHelper> loadData;
+
+ std::unordered_map<std::pair<uint32, Difficulty>, SpellInfoLoadHelper> loadData;
std::unordered_map<int32, BattlePetSpeciesEntry const*> battlePetSpeciesByCreature;
std::unordered_map<uint32, BattlePetSpeciesEntry const*> battlePetSpeciesBySpellId;
@@ -2360,9 +2430,6 @@ void SpellMgr::LoadSpellInfoStore()
if (battlePetSpecies->CreatureID)
battlePetSpeciesByCreature[battlePetSpecies->CreatureID] = battlePetSpecies;
- std::unordered_map<int32, SpellEffectEntryMap> effectsBySpell;
- std::unordered_map<uint32, SpellVisualMap> visualsBySpell;
-
for (SpellEffectEntry const* effect : sSpellEffectStore)
{
ASSERT(effect->EffectIndex < MAX_SPELL_EFFECTS, "MAX_SPELL_EFFECTS must be at least %d", effect->EffectIndex + 1);
@@ -2371,11 +2438,7 @@ void SpellMgr::LoadSpellInfoStore()
ASSERT(effect->ImplicitTarget[0] < TOTAL_SPELL_TARGETS, "TOTAL_SPELL_TARGETS must be at least %u", effect->ImplicitTarget[0] + 1);
ASSERT(effect->ImplicitTarget[1] < TOTAL_SPELL_TARGETS, "TOTAL_SPELL_TARGETS must be at least %u", effect->ImplicitTarget[1] + 1);
- SpellEffectEntryVector& effectsForDifficulty = effectsBySpell[effect->SpellID][effect->DifficultyID];
- if (effectsForDifficulty.size() <= std::size_t(effect->EffectIndex))
- effectsForDifficulty.resize(std::size_t(effect->EffectIndex + 1));
-
- effectsForDifficulty[effect->EffectIndex] = effect;
+ loadData[{ effect->SpellID, Difficulty(effect->DifficultyID) }].Effects[effect->EffectIndex] = effect;
if (effect->Effect == SPELL_EFFECT_SUMMON)
if (SummonPropertiesEntry const* summonProperties = sSummonPropertiesStore.LookupEntry(effect->EffectMiscValue[1]))
@@ -2385,68 +2448,131 @@ void SpellMgr::LoadSpellInfoStore()
}
for (SpellAuraOptionsEntry const* auraOptions : sSpellAuraOptionsStore)
- if (!auraOptions->DifficultyID) // TODO: implement
- loadData[auraOptions->SpellID].AuraOptions = auraOptions;
+ loadData[{ auraOptions->SpellID, Difficulty(auraOptions->DifficultyID) }].AuraOptions = auraOptions;
for (SpellAuraRestrictionsEntry const* auraRestrictions : sSpellAuraRestrictionsStore)
- if (!auraRestrictions->DifficultyID) // TODO: implement
- loadData[auraRestrictions->SpellID].AuraRestrictions = auraRestrictions;
+ loadData[{ auraRestrictions->SpellID, Difficulty(auraRestrictions->DifficultyID) }].AuraRestrictions = auraRestrictions;
for (SpellCastingRequirementsEntry const* castingRequirements : sSpellCastingRequirementsStore)
- loadData[castingRequirements->SpellID].CastingRequirements = castingRequirements;
+ loadData[{ castingRequirements->SpellID, DIFFICULTY_NONE }].CastingRequirements = castingRequirements;
for (SpellCategoriesEntry const* categories : sSpellCategoriesStore)
- if (!categories->DifficultyID) // TODO: implement
- loadData[categories->SpellID].Categories = categories;
+ loadData[{ categories->SpellID, Difficulty(categories->DifficultyID) }].Categories = categories;
for (SpellClassOptionsEntry const* classOptions : sSpellClassOptionsStore)
- loadData[classOptions->SpellID].ClassOptions = classOptions;
+ loadData[{ classOptions->SpellID, DIFFICULTY_NONE }].ClassOptions = classOptions;
for (SpellCooldownsEntry const* cooldowns : sSpellCooldownsStore)
- if (!cooldowns->DifficultyID) // TODO: implement
- loadData[cooldowns->SpellID].Cooldowns = cooldowns;
+ loadData[{ cooldowns->SpellID, Difficulty(cooldowns->DifficultyID) }].Cooldowns = cooldowns;
for (SpellEquippedItemsEntry const* equippedItems : sSpellEquippedItemsStore)
- loadData[equippedItems->SpellID].EquippedItems = equippedItems;
+ loadData[{ equippedItems->SpellID, DIFFICULTY_NONE }].EquippedItems = equippedItems;
for (SpellInterruptsEntry const* interrupts : sSpellInterruptsStore)
- if (!interrupts->DifficultyID) // TODO: implement
- loadData[interrupts->SpellID].Interrupts = interrupts;
+ loadData[{ interrupts->SpellID, Difficulty(interrupts->DifficultyID) }].Interrupts = interrupts;
for (SpellLevelsEntry const* levels : sSpellLevelsStore)
- if (!levels->DifficultyID) // TODO: implement
- loadData[levels->SpellID].Levels = levels;
+ loadData[{ levels->SpellID, Difficulty(levels->DifficultyID) }].Levels = levels;
for (SpellMiscEntry const* misc : sSpellMiscStore)
- if (!misc->DifficultyID)
- loadData[misc->SpellID].Misc = misc;
+ loadData[{ misc->SpellID, Difficulty(misc->DifficultyID) }].Misc = misc;
+
+ for (SpellPowerEntry const* power : sSpellPowerStore)
+ {
+ Difficulty difficulty = DIFFICULTY_NONE;
+ uint8 index = power->OrderIndex;
+ if (SpellPowerDifficultyEntry const* powerDifficulty = sSpellPowerDifficultyStore.LookupEntry(power->ID))
+ {
+ difficulty = Difficulty(powerDifficulty->DifficultyID);
+ index = powerDifficulty->OrderIndex;
+ }
+
+ loadData[{ power->SpellID, difficulty }].Powers[index] = power;
+ }
for (SpellReagentsEntry const* reagents : sSpellReagentsStore)
- loadData[reagents->SpellID].Reagents = reagents;
+ loadData[{ reagents->SpellID, DIFFICULTY_NONE }].Reagents = reagents;
for (SpellScalingEntry const* scaling : sSpellScalingStore)
- loadData[scaling->SpellID].Scaling = scaling;
+ loadData[{ scaling->SpellID, DIFFICULTY_NONE }].Scaling = scaling;
for (SpellShapeshiftEntry const* shapeshift : sSpellShapeshiftStore)
- loadData[shapeshift->SpellID].Shapeshift = shapeshift;
+ loadData[{ shapeshift->SpellID, DIFFICULTY_NONE }].Shapeshift = shapeshift;
for (SpellTargetRestrictionsEntry const* targetRestrictions : sSpellTargetRestrictionsStore)
- if (!targetRestrictions->DifficultyID) // TODO: implement
- loadData[targetRestrictions->SpellID].TargetRestrictions = targetRestrictions;
+ loadData[{ targetRestrictions->SpellID, Difficulty(targetRestrictions->DifficultyID) }].TargetRestrictions = targetRestrictions;
for (SpellTotemsEntry const* totems : sSpellTotemsStore)
- loadData[totems->SpellID].Totems = totems;
+ loadData[{ totems->SpellID, DIFFICULTY_NONE }].Totems = totems;
for (SpellXSpellVisualEntry const* visual : sSpellXSpellVisualStore)
- visualsBySpell[visual->SpellID][visual->DifficultyID].push_back(visual);
+ {
+ SpellVisualVector& visuals = loadData[{ visual->SpellID, Difficulty(visual->DifficultyID) }].Visuals;
+
+ auto where = std::lower_bound(visuals.begin(), visuals.end(), visual, [](SpellXSpellVisualEntry const* first, SpellXSpellVisualEntry const* second)
+ {
+ return first->CasterPlayerConditionID > second->CasterPlayerConditionID;
+ });
- for (uint32 i = 0; i < sSpellNameStore.GetNumRows(); ++i)
+ // sorted with unconditional visuals being last
+ visuals.insert(where, visual);
+ }
+
+ for (std::pair<std::pair<uint32, Difficulty> const, SpellInfoLoadHelper>& data : loadData)
{
- if (SpellNameEntry const* spellNameEntry = sSpellNameStore.LookupEntry(i))
+ SpellNameEntry const* spellNameEntry = sSpellNameStore.LookupEntry(data.first.first);
+ if (!spellNameEntry)
+ continue;
+
+ SpellVisualVector visuals = data.second.Visuals; // copy, need to ensure source remains unmodified
+
+ // fill blanks
+ if (DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(data.first.second))
{
- loadData[i].Entry = spellNameEntry;
- mSpellInfoMap[i] = new SpellInfo(loadData[i], effectsBySpell[i], std::move(visualsBySpell[i]));
+ do
+ {
+ if (SpellInfoLoadHelper const* fallbackData = Trinity::Containers::MapGetValuePtr(loadData, { data.first.first, Difficulty(difficultyEntry->FallbackDifficultyID) }))
+ {
+ if (!data.second.AuraOptions)
+ data.second.AuraOptions = fallbackData->AuraOptions;
+
+ if (!data.second.AuraRestrictions)
+ data.second.AuraRestrictions = fallbackData->AuraRestrictions;
+
+ if (!data.second.Categories)
+ data.second.Categories = fallbackData->Categories;
+
+ if (!data.second.Cooldowns)
+ data.second.Cooldowns = fallbackData->Cooldowns;
+
+ for (std::size_t i = 0; i < data.second.Effects.size(); ++i)
+ if (!data.second.Effects[i])
+ data.second.Effects[i] = fallbackData->Effects[i];
+
+ if (!data.second.Interrupts)
+ data.second.Interrupts = fallbackData->Interrupts;
+
+ if (!data.second.Levels)
+ data.second.Levels = fallbackData->Levels;
+
+ if (!data.second.Misc)
+ data.second.Misc = fallbackData->Misc;
+
+ for (std::size_t i = 0; i < fallbackData->Powers.size(); ++i)
+ if (!data.second.Powers[i])
+ data.second.Powers[i] = fallbackData->Powers[i];
+
+ if (!data.second.TargetRestrictions)
+ data.second.TargetRestrictions = fallbackData->TargetRestrictions;
+
+ visuals.insert(visuals.end(), fallbackData->Visuals.begin(), fallbackData->Visuals.end());
+ }
+
+ difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID);
+ } while (difficultyEntry);
}
+
+ mSpellInfoMap.emplace(spellNameEntry, data.first.second, data.second, std::move(visuals));
}
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo store in %u ms", GetMSTimeDiffToNow(oldMSTime));
@@ -2454,24 +2580,19 @@ void SpellMgr::LoadSpellInfoStore()
void SpellMgr::UnloadSpellInfoStore()
{
- for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
- delete mSpellInfoMap[i];
-
mSpellInfoMap.clear();
}
void SpellMgr::UnloadSpellInfoImplicitTargetConditionLists()
{
- for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
- if (mSpellInfoMap[i])
- mSpellInfoMap[i]->_UnloadImplicitTargetConditionLists();
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
+ const_cast<SpellInfo&>(spellInfo)._UnloadImplicitTargetConditionLists();
}
void SpellMgr::LoadSpellInfoCustomAttributes()
{
uint32 oldMSTime = getMSTime();
uint32 oldMSTime2 = oldMSTime;
- SpellInfo* spellInfo = NULL;
QueryResult result = WorldDatabase.Query("SELECT entry, attributes FROM spell_custom_attr");
@@ -2487,24 +2608,27 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
uint32 spellId = fields[0].GetUInt32();
uint32 attributes = fields[1].GetUInt32();
- spellInfo = _GetSpellInfo(spellId);
- if (!spellInfo)
+ auto spells = _GetSpellInfo(spellId);
+ if (spells.begin() == spells.end())
{
TC_LOG_ERROR("sql.sql", "Table `spell_custom_attr` has wrong spell (entry: %u), ignored.", spellId);
continue;
}
// TODO: validate attributes
- if (attributes & SPELL_ATTR0_CU_SHARE_DAMAGE)
+ for (SpellInfo const& spellInfo : spells)
{
- if (!spellInfo->HasEffect(SPELL_EFFECT_SCHOOL_DAMAGE))
+ if (attributes & SPELL_ATTR0_CU_SHARE_DAMAGE)
{
- TC_LOG_ERROR("sql.sql", "Spell %u listed in table `spell_custom_attr` with SPELL_ATTR0_CU_SHARE_DAMAGE has no SPELL_EFFECT_SCHOOL_DAMAGE, ignored.", spellId);
- continue;
+ if (!spellInfo.HasEffect(SPELL_EFFECT_SCHOOL_DAMAGE))
+ {
+ TC_LOG_ERROR("sql.sql", "Spell %u listed in table `spell_custom_attr` with SPELL_ATTR0_CU_SHARE_DAMAGE has no SPELL_EFFECT_SCHOOL_DAMAGE, ignored.", spellId);
+ continue;
+ }
}
- }
- spellInfo->AttributesCu |= attributes;
+ const_cast<SpellInfo&>(spellInfo).AttributesCu |= attributes;
+ }
++count;
} while (result->NextRow());
@@ -2516,13 +2640,10 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(i))
talentSpells.insert(talentInfo->SpellID);
- for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
{
- spellInfo = mSpellInfoMap[i];
- if (!spellInfo)
- continue;
-
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ SpellInfo* spellInfoMutable = const_cast<SpellInfo*>(&spellInfo);
+ for (SpellEffectInfo const* effect : spellInfoMutable->GetEffects())
{
if (!effect)
continue;
@@ -2535,7 +2656,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
case SPELL_AURA_AOE_CHARM:
case SPELL_AURA_MOD_FEAR:
case SPELL_AURA_MOD_STUN:
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
break;
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_PERIODIC_DAMAGE:
@@ -2547,7 +2668,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
case SPELL_AURA_OBS_MOD_HEALTH:
case SPELL_AURA_OBS_MOD_POWER:
case SPELL_AURA_POWER_BURN:
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
break;
}
@@ -2559,7 +2680,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
case SPELL_EFFECT_HEAL:
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE;
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE;
break;
case SPELL_EFFECT_POWER_DRAIN:
case SPELL_EFFECT_POWER_BURN:
@@ -2569,17 +2690,17 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
case SPELL_EFFECT_ENERGIZE_PCT:
case SPELL_EFFECT_ENERGIZE:
case SPELL_EFFECT_HEAL_MECHANICAL:
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
break;
case SPELL_EFFECT_CHARGE:
case SPELL_EFFECT_CHARGE_DEST:
case SPELL_EFFECT_JUMP:
case SPELL_EFFECT_JUMP_DEST:
case SPELL_EFFECT_LEAP_BACK:
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_CHARGE;
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_CHARGE;
break;
case SPELL_EFFECT_PICKPOCKET:
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET;
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET;
break;
case SPELL_EFFECT_ENCHANT_ITEM:
case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
@@ -2587,7 +2708,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
case SPELL_EFFECT_ENCHANT_HELD_ITEM:
{
// only enchanting profession enchantments procs can stack
- if (IsPartOfSkillLine(SKILL_ENCHANTING, i))
+ if (IsPartOfSkillLine(SKILL_ENCHANTING, spellInfo.Id))
{
uint32 enchantId = effect->MiscValue;
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
@@ -2599,17 +2720,16 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
if (enchant->Effect[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
continue;
- SpellInfo* procInfo = _GetSpellInfo(enchant->EffectArg[s]);
- if (!procInfo)
- continue;
+ for (SpellInfo const& procInfo : _GetSpellInfo(enchant->EffectArg[s]))
+ {
+ // if proced directly from enchantment, not via proc aura
+ // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly
+ // however its not expected to stack so this check is good
+ if (procInfo.HasAura(SPELL_AURA_PROC_TRIGGER_SPELL))
+ continue;
- // if proced directly from enchantment, not via proc aura
- // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly
- // however its not expected to stack so this check is good
- if (procInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_PROC_TRIGGER_SPELL))
- continue;
-
- procInfo->AttributesCu |= SPELL_ATTR0_CU_ENCHANT_PROC;
+ const_cast<SpellInfo&>(procInfo).AttributesCu |= SPELL_ATTR0_CU_ENCHANT_PROC;
+ }
}
}
break;
@@ -2618,10 +2738,10 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
}
// spells ignoring hit result should not be binary
- if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
+ if (!spellInfoMutable->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
{
bool setFlag = false;
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfoMutable->GetEffects())
{
if (!effect)
continue;
@@ -2657,23 +2777,23 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
default:
{
// No value and not interrupt cast or crowd control without SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY flag
- if (!effect->CalcValue() && !((effect->Effect == SPELL_EFFECT_INTERRUPT_CAST || spellInfo->HasAttribute(SPELL_ATTR0_CU_AURA_CC)) && !spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)))
+ if (!effect->CalcValue() && !((effect->Effect == SPELL_EFFECT_INTERRUPT_CAST || spellInfoMutable->HasAttribute(SPELL_ATTR0_CU_AURA_CC)) && !spellInfoMutable->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)))
break;
// Sindragosa Frost Breath
- if (spellInfo->Id == 69649 || spellInfo->Id == 71056 || spellInfo->Id == 71057 || spellInfo->Id == 71058 || spellInfo->Id == 73061 || spellInfo->Id == 73062 || spellInfo->Id == 73063 || spellInfo->Id == 73064)
+ if (spellInfoMutable->Id == 69649 || spellInfoMutable->Id == 71056 || spellInfoMutable->Id == 71057 || spellInfoMutable->Id == 71058 || spellInfoMutable->Id == 73061 || spellInfoMutable->Id == 73062 || spellInfoMutable->Id == 73063 || spellInfoMutable->Id == 73064)
break;
// Frostbolt
- if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->SpellFamilyFlags[0] & 0x20))
+ if (spellInfoMutable->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfoMutable->SpellFamilyFlags[0] & 0x20))
break;
// Frost Fever
- if (spellInfo->Id == 55095)
+ if (spellInfoMutable->Id == 55095)
break;
// Haunt
- if (spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellInfo->SpellFamilyFlags[1] & 0x40000))
+ if (spellInfoMutable->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellInfoMutable->SpellFamilyFlags[1] & 0x40000))
break;
setFlag = true;
@@ -2683,7 +2803,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
if (setFlag)
{
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY_SPELL;
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_BINARY_SPELL;
break;
}
}
@@ -2691,61 +2811,58 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
}
// Remove normal school mask to properly calculate damage
- if ((spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) && (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_MAGIC))
+ if ((spellInfoMutable->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) && (spellInfoMutable->SchoolMask & SPELL_SCHOOL_MASK_MAGIC))
{
- spellInfo->SchoolMask &= ~SPELL_SCHOOL_MASK_NORMAL;
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC;
+ spellInfoMutable->SchoolMask &= ~SPELL_SCHOOL_MASK_NORMAL;
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC;
}
- if (!spellInfo->_IsPositiveEffect(EFFECT_0, false))
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0;
+ if (!spellInfoMutable->_IsPositiveEffect(EFFECT_0, false))
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0;
- if (!spellInfo->_IsPositiveEffect(EFFECT_1, false))
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF1;
+ if (!spellInfoMutable->_IsPositiveEffect(EFFECT_1, false))
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF1;
- if (!spellInfo->_IsPositiveEffect(EFFECT_2, false))
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF2;
+ if (!spellInfoMutable->_IsPositiveEffect(EFFECT_2, false))
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF2;
- if (talentSpells.count(spellInfo->Id))
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_IS_TALENT;
+ if (talentSpells.count(spellInfoMutable->Id))
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_IS_TALENT;
- switch (spellInfo->SpellFamilyName)
+ switch (spellInfoMutable->SpellFamilyName)
{
case SPELLFAMILY_WARRIOR:
// Shout / Piercing Howl
- if (spellInfo->SpellFamilyFlags[0] & 0x20000/* || spellInfo->SpellFamilyFlags[1] & 0x20*/)
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
+ if (spellInfoMutable->SpellFamilyFlags[0] & 0x20000/* || spellInfo->SpellFamilyFlags[1] & 0x20*/)
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
break;
case SPELLFAMILY_DRUID:
// Roar
- if (spellInfo->SpellFamilyFlags[0] & 0x8)
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
+ if (spellInfoMutable->SpellFamilyFlags[0] & 0x8)
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
break;
case SPELLFAMILY_GENERIC:
// Stoneclaw Totem effect
- if (spellInfo->Id == 5729)
- spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
+ if (spellInfoMutable->Id == 5729)
+ spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
break;
default:
break;
}
- spellInfo->_InitializeExplicitTargetMask();
+ spellInfoMutable->_InitializeExplicitTargetMask();
}
// addition for binary spells, ommit spells triggering other spells
- for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
{
- spellInfo = mSpellInfoMap[i];
- if (!spellInfo)
- continue;
-
- if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
+ SpellInfo* spellInfoMutable = const_cast<SpellInfo*>(&spellInfo);
+ if (spellInfoMutable->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
continue;
bool allNonBinary = true;
bool overrideAttr = false;
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfoMutable->GetEffects())
{
if (!effect)
continue;
@@ -2756,7 +2873,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
{
case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
- if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(effect->TriggerSpell))
+ if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(effect->TriggerSpell, DIFFICULTY_NONE))
{
overrideAttr = true;
if (triggerSpell->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
@@ -2770,7 +2887,7 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
}
if (overrideAttr && allNonBinary)
- spellInfo->AttributesCu &= ~SPELL_ATTR0_CU_BINARY_SPELL;
+ spellInfoMutable->AttributesCu &= ~SPELL_ATTR0_CU_BINARY_SPELL;
}
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo custom attributes in %u ms", GetMSTimeDiffToNow(oldMSTime));
@@ -2780,14 +2897,15 @@ inline void ApplySpellFix(std::initializer_list<uint32> spellIds, void(*fix)(Spe
{
for (uint32 spellId : spellIds)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (!spellInfo)
+ auto range = _GetSpellInfo(spellId);
+ if (range.begin() == range.end())
{
TC_LOG_ERROR("server.loading", "Spell info correction specified for non-existing spell %u", spellId);
continue;
}
- fix(const_cast<SpellInfo*>(spellInfo));
+ for (SpellInfo const& spellInfo : range)
+ fix(&const_cast<SpellInfo&>(spellInfo));
}
}
@@ -3724,14 +3842,13 @@ void SpellMgr::LoadSpellInfoCorrections()
const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
});
- SpellInfo* spellInfo = NULL;
- for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
+ for (SpellInfo const& s : mSpellInfoMap)
{
- spellInfo = (SpellInfo*)mSpellInfoMap[i];
+ SpellInfo* spellInfo = &const_cast<SpellInfo&>(s);
if (!spellInfo)
continue;
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
+ for (SpellEffectInfo const* effect : spellInfo->GetEffects())
{
if (!effect)
continue;
@@ -3739,7 +3856,7 @@ void SpellMgr::LoadSpellInfoCorrections()
if (effect->IsEffect() && (effect->TargetA.GetTarget() == TARGET_DEST_TRAJ || effect->TargetB.GetTarget() == TARGET_DEST_TRAJ))
{
// Get triggered spell if any
- if (SpellInfo* spellInfoTrigger = const_cast<SpellInfo*>(GetSpellInfo(effect->TriggerSpell)))
+ if (SpellInfo* spellInfoTrigger = const_cast<SpellInfo*>(GetSpellInfo(effect->TriggerSpell, DIFFICULTY_NONE)))
{
float maxRangeMain = spellInfo->GetMaxRange();
float maxRangeTrigger = spellInfoTrigger->GetMaxRange();
@@ -3768,11 +3885,11 @@ void SpellMgr::LoadSpellInfoCorrections()
}
// disable proc for magnet auras, they're handled differently
- if (spellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_SPELL_MAGNET))
+ if (spellInfo->HasAura(SPELL_AURA_SPELL_MAGNET))
spellInfo->ProcFlags = 0;
// due to the way spell system works, unit would change orientation in Spell::_cast
- if (spellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_CONTROL_VEHICLE))
+ if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
spellInfo->AttributesEx5 |= SPELL_ATTR5_DONT_TURN_DURING_CAST;
if (spellInfo->ActiveIconFileDataId == 135754) // flight
@@ -3793,14 +3910,11 @@ void SpellMgr::LoadSpellInfoSpellSpecificAndAuraState()
{
uint32 oldMSTime = getMSTime();
- for (SpellInfo* spellInfo : mSpellInfoMap)
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
{
- if (!spellInfo)
- continue;
-
// AuraState depends on SpellSpecific
- spellInfo->_LoadSpellSpecific();
- spellInfo->_LoadAuraState();
+ const_cast<SpellInfo&>(spellInfo)._LoadSpellSpecific();
+ const_cast<SpellInfo&>(spellInfo)._LoadAuraState();
}
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo SpellSpecific and AuraState in %u ms", GetMSTimeDiffToNow(oldMSTime));
@@ -3810,13 +3924,8 @@ void SpellMgr::LoadSpellInfoDiminishing()
{
uint32 oldMSTime = getMSTime();
- for (SpellInfo* spellInfo : mSpellInfoMap)
- {
- if (!spellInfo)
- continue;
-
- spellInfo->_LoadSpellDiminishInfo();
- }
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
+ const_cast<SpellInfo&>(spellInfo)._LoadSpellDiminishInfo();
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo diminishing infos in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
@@ -3825,13 +3934,8 @@ void SpellMgr::LoadSpellInfoImmunities()
{
uint32 oldMSTime = getMSTime();
- for (SpellInfo* spellInfo : mSpellInfoMap)
- {
- if (!spellInfo)
- continue;
-
- spellInfo->_LoadImmunityInfo();
- }
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
+ const_cast<SpellInfo&>(spellInfo)._LoadImmunityInfo();
TC_LOG_INFO("server.loading", ">> Loaded SpellInfo immunity infos in %u ms", GetMSTimeDiffToNow(oldMSTime));
}
@@ -3845,7 +3949,7 @@ void SpellMgr::LoadPetFamilySpellsStore()
for (SkillLineAbilityEntry const* skillLine : sSkillLineAbilityStore)
{
- SpellInfo const* spellInfo = GetSpellInfo(skillLine->Spell);
+ SpellInfo const* spellInfo = GetSpellInfo(skillLine->Spell, DIFFICULTY_NONE);
if (!spellInfo)
continue;
@@ -3890,7 +3994,7 @@ void SpellMgr::LoadSpellTotemModel()
uint8 race = fields[1].GetUInt8();
uint32 displayId = fields[2].GetUInt32();
- SpellInfo const* spellEntry = GetSpellInfo(spellId);
+ SpellInfo const* spellEntry = GetSpellInfo(spellId, DIFFICULTY_NONE);
if (!spellEntry)
{
TC_LOG_ERROR("sql.sql", "SpellID: %u in `spell_totem_model` table could not be found in dbc, skipped.", spellId);