diff options
101 files changed, 1599 insertions, 1764 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 625ad4ef783..7f03bea5193 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -511,6 +511,7 @@ CREATE TABLE `character_aura` ( `spell` int(10) unsigned NOT NULL, `effectMask` int(10) unsigned NOT NULL, `recalculateMask` int(10) unsigned NOT NULL DEFAULT '0', + `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0', `stackCount` tinyint(3) unsigned NOT NULL DEFAULT '1', `maxDuration` int(11) NOT NULL DEFAULT '0', `remainTime` int(11) NOT NULL DEFAULT '0', @@ -3342,6 +3343,7 @@ CREATE TABLE `pet_aura` ( `spell` int(10) unsigned NOT NULL, `effectMask` int(10) unsigned NOT NULL, `recalculateMask` int(10) unsigned NOT NULL DEFAULT '0', + `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0', `stackCount` tinyint(3) unsigned NOT NULL DEFAULT '1', `maxDuration` int(11) NOT NULL DEFAULT '0', `remainTime` int(11) NOT NULL DEFAULT '0', @@ -3774,8 +3776,8 @@ INSERT INTO `updates` VALUES ('2020_04_24_00_characters.sql','85E2E0395A9457A53D73A9E0A7BB39B7E4C429BF','RELEASED','2020-04-24 22:04:59',0), ('2020_04_25_00_characters_2017_04_03_00_characters.sql','00FA3EFADAF807AC96619A3FE47216E21C3FCB19','RELEASED','2020-04-25 00:00:00',0), ('2020_04_26_00_characters_2017_04_12_00_characters.sql','86AA94DA9B1EA283101100886C10F648C0CE6494','RELEASED','2020-04-26 00:00:00',0), -('2020_04_26_01_characters_2017_04_12_01_characters.sql','5A8A1215E3A2356722F52CD7A64BBE03D21FBEA3','RELEASED','2020-04-26 00:00:00',0); - +('2020_04_26_01_characters_2017_04_12_01_characters.sql','5A8A1215E3A2356722F52CD7A64BBE03D21FBEA3','RELEASED','2020-04-26 00:00:00',0), +('2020_06_12_00_characters.sql','DF16C99EFACA4DFADDDF35644AAC63F9B4AA2BD6','RELEASED','2020-06-11 16:24:56',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/master/2020_06_12_00_characters.sql b/sql/updates/characters/master/2020_06_12_00_characters.sql new file mode 100644 index 00000000000..885111dc1f7 --- /dev/null +++ b/sql/updates/characters/master/2020_06_12_00_characters.sql @@ -0,0 +1,2 @@ +ALTER TABLE `character_aura` ADD `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `recalculateMask`; +ALTER TABLE `pet_aura` ADD `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `recalculateMask`; diff --git a/src/common/Utilities/IteratorPair.h b/src/common/Utilities/IteratorPair.h index 1e06f2ef920..319fadada09 100644 --- a/src/common/Utilities/IteratorPair.h +++ b/src/common/Utilities/IteratorPair.h @@ -44,6 +44,12 @@ namespace Trinity namespace Containers { + template<typename iterator> + constexpr Trinity::IteratorPair<iterator> MakeIteratorPair(std::pair<iterator, iterator> iterators) + { + return iterators; + } + template<class M> inline auto MapEqualRange(M& map, typename M::key_type const& key) -> IteratorPair<decltype(map.begin())> { diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 24ae14580f9..c17fe356680 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -86,7 +86,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime, entranceId FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_AURA_EFFECTS, "SELECT casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount FROM character_aura_effect WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, timer FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC); @@ -343,8 +343,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_TRANSMOG_OUTFIT, "DELETE FROM character_transmog_outfits WHERE setguid=?", CONNECTION_ASYNC); // Auras - PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_AURA_EFFECT, "INSERT INTO character_aura_effect (guid, casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); @@ -715,7 +715,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE owner = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_AURA_EFFECT, "SELECT casterGuid, spell, effectMask, effectIndex, amount, baseAmount FROM pet_aura_effect WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time, categoryId, categoryEnd FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH); @@ -730,8 +730,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_PET_SPELL_CHARGES, "INSERT INTO pet_spell_charges (guid, categoryId, rechargeStart, rechargeEnd) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PET_SPELL_BY_SPELL, "DELETE FROM pet_spell WHERE guid = ? and spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PET_SPELL, "INSERT INTO pet_spell (guid, spell, active) VALUES (?, ?, ?)", CONNECTION_BOTH); - PrepareStatement(CHAR_INS_PET_AURA, "INSERT INTO pet_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); + PrepareStatement(CHAR_INS_PET_AURA, "INSERT INTO pet_aura (guid, casterGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); PrepareStatement(CHAR_INS_PET_AURA_EFFECT, "INSERT INTO pet_aura_effect (guid, casterGuid, spell, effectMask, effectIndex, amount, baseAmount) " "VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND id = ?", CONNECTION_SYNCH); diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index fd42e251915..2f2461b5ab0 100644 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -20,6 +20,7 @@ #include "Creature.h" #include "CreatureAIImpl.h" #include "Log.h" +#include "Map.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "Player.h" @@ -55,7 +56,7 @@ void AggressorAI::UpdateAI(uint32 /*diff*/) void CombatAI::InitializeAI() { for (uint32 i = 0; i < MAX_CREATURE_SPELLS; ++i) - if (me->m_spells[i] && sSpellMgr->GetSpellInfo(me->m_spells[i])) + if (me->m_spells[i] && sSpellMgr->GetSpellInfo(me->m_spells[i], me->GetMap()->GetDifficultyID())) spells.push_back(me->m_spells[i]); CreatureAI::InitializeAI(); @@ -69,18 +70,22 @@ void CombatAI::Reset() void CombatAI::JustDied(Unit* killer) { for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) - if (AISpellInfo[*i].condition == AICOND_DIE) - me->CastSpell(killer, *i, true); + if (AISpellInfoType const* info = GetAISpellInfo(*i, me->GetMap()->GetDifficultyID())) + if (info->condition == AICOND_DIE) + me->CastSpell(killer, *i, true); } void CombatAI::EnterCombat(Unit* who) { for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) { - if (AISpellInfo[*i].condition == AICOND_AGGRO) - me->CastSpell(who, *i, false); - else if (AISpellInfo[*i].condition == AICOND_COMBAT) - events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand32() % AISpellInfo[*i].cooldown); + if (AISpellInfoType const* info = GetAISpellInfo(*i, me->GetMap()->GetDifficultyID())) + { + if (info->condition == AICOND_AGGRO) + me->CastSpell(who, *i, false); + else if (info->condition == AICOND_COMBAT) + events.ScheduleEvent(*i, info->cooldown + rand32() % info->cooldown); + } } } @@ -97,7 +102,8 @@ void CombatAI::UpdateAI(uint32 diff) if (uint32 spellId = events.ExecuteEvent()) { DoCast(spellId); - events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand32() % AISpellInfo[spellId].cooldown); + if (AISpellInfoType const* info = GetAISpellInfo(spellId, me->GetMap()->GetDifficultyID())) + events.ScheduleEvent(spellId, info->cooldown + rand32() % info->cooldown); } else DoMeleeAttackIfReady(); @@ -118,8 +124,10 @@ void CasterAI::InitializeAI() m_attackDist = 30.0f; for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr) - if (AISpellInfo[*itr].condition == AICOND_COMBAT && m_attackDist > GetAISpellInfo(*itr)->maxRange) - m_attackDist = GetAISpellInfo(*itr)->maxRange; + if (AISpellInfoType const* info = GetAISpellInfo(*itr, me->GetMap()->GetDifficultyID())) + if (info->condition == AICOND_COMBAT && m_attackDist > info->maxRange) + m_attackDist = info->maxRange; + if (m_attackDist == 30.0f) m_attackDist = MELEE_RANGE; } @@ -133,17 +141,20 @@ void CasterAI::EnterCombat(Unit* who) uint32 count = 0; for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr, ++count) { - if (AISpellInfo[*itr].condition == AICOND_AGGRO) - me->CastSpell(who, *itr, false); - else if (AISpellInfo[*itr].condition == AICOND_COMBAT) + if (AISpellInfoType const* info = GetAISpellInfo(*itr, me->GetMap()->GetDifficultyID())) { - uint32 cooldown = GetAISpellInfo(*itr)->realCooldown; - if (count == spell) + if (info->condition == AICOND_AGGRO) + me->CastSpell(who, *itr, false); + else if (info->condition == AICOND_COMBAT) { - DoCast(spells[spell]); - cooldown += me->GetCurrentSpellCastTime(*itr); + uint32 cooldown = info->realCooldown; + if (count == spell) + { + DoCast(spells[spell]); + cooldown += me->GetCurrentSpellCastTime(*itr); + } + events.ScheduleEvent(*itr, cooldown); } - events.ScheduleEvent(*itr, cooldown); } } } @@ -168,7 +179,8 @@ void CasterAI::UpdateAI(uint32 diff) { DoCast(spellId); uint32 casttime = me->GetCurrentSpellCastTime(spellId); - events.ScheduleEvent(spellId, (casttime ? casttime : 500) + GetAISpellInfo(spellId)->realCooldown); + if (AISpellInfoType const* info = GetAISpellInfo(spellId, me->GetMap()->GetDifficultyID())) + events.ScheduleEvent(spellId, (casttime ? casttime : 500) + info->realCooldown); } } @@ -181,7 +193,7 @@ ArcherAI::ArcherAI(Creature* c) : CreatureAI(c) if (!me->m_spells[0]) TC_LOG_ERROR("misc", "ArcherAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->m_spells[0]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->m_spells[0], me->GetMap()->GetDifficultyID()); m_minRange = spellInfo ? spellInfo->GetMinRange(false) : 0; if (!m_minRange) @@ -230,7 +242,7 @@ TurretAI::TurretAI(Creature* c) : CreatureAI(c) if (!me->m_spells[0]) TC_LOG_ERROR("misc", "TurretAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry()); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->m_spells[0]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->m_spells[0], me->GetMap()->GetDifficultyID()); m_minRange = spellInfo ? spellInfo->GetMinRange(false) : 0; me->m_CombatDistance = spellInfo ? spellInfo->GetMaxRange(false) : 0; me->m_SightDistance = me->m_CombatDistance; diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index cc0969ab15d..a39e4a8dfc0 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -20,6 +20,7 @@ #include "Errors.h" #include "Group.h" #include "Log.h" +#include "Map.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "Pet.h" @@ -146,7 +147,7 @@ void PetAI::UpdateAI(uint32 diff) if (!spellID) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID, me->GetMap()->GetDifficultyID()); if (!spellInfo) continue; @@ -184,7 +185,7 @@ void PetAI::UpdateAI(uint32 diff) } } - if (spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_JUMP_DEST)) + if (spellInfo->HasEffect(SPELL_EFFECT_JUMP_DEST)) { if (!spellUsed) delete spell; diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp index a2f0f8f664b..4d2bda5faa0 100644 --- a/src/server/game/AI/CoreAI/TotemAI.cpp +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -53,7 +53,7 @@ void TotemAI::UpdateAI(uint32 /*diff*/) return; // Search spell - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->ToTotem()->GetSpell()); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->ToTotem()->GetSpell(), me->GetMap()->GetDifficultyID()); if (!spellInfo) return; diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 14b162ca4a6..8d1ed85a6e8 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -18,6 +18,7 @@ #include "UnitAI.h" #include "Creature.h" #include "CreatureAIImpl.h" +#include "Map.h" #include "MotionMaster.h" #include "Player.h" #include "QuestDef.h" @@ -90,7 +91,7 @@ bool UnitAI::DoSpellAttackIfReady(uint32 spellId) if (me->HasUnitState(UNIT_STATE_CASTING) || !me->isAttackReady()) return true; - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, me->GetMap()->GetDifficultyID())) { if (me->IsWithinCombatRange(me->GetVictim(), spellInfo->GetMaxRange(false))) { @@ -116,8 +117,11 @@ void UnitAI::SelectTargetList(std::list<Unit*>& targetList, uint32 num, SelectAg void UnitAI::DoCast(uint32 spellId) { Unit* target = NULL; + AITarget aiTargetType = AITARGET_SELF; + if (AISpellInfoType const* info = GetAISpellInfo(spellId, me->GetMap()->GetDifficultyID())) + aiTargetType = info->target; - switch (AISpellInfo[spellId].target) + switch (aiTargetType) { default: case AITARGET_SELF: @@ -128,7 +132,7 @@ void UnitAI::DoCast(uint32 spellId) break; case AITARGET_ENEMY: { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, me->GetMap()->GetDifficultyID())) { bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS); target = SelectTarget(SELECT_TARGET_RANDOM, 0, spellInfo->GetMaxRange(false), playerOnly); @@ -143,7 +147,7 @@ void UnitAI::DoCast(uint32 spellId) break; case AITARGET_DEBUFF: { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, me->GetMap()->GetDifficultyID())) { bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS); float range = spellInfo->GetMaxRange(false); @@ -190,16 +194,9 @@ void UnitAI::DoCastAOE(uint32 spellId, bool triggered) void UnitAI::FillAISpellInfo() { - AISpellInfo = new AISpellInfoType[sSpellMgr->GetSpellInfoStoreSize()]; - - AISpellInfoType* AIInfo = AISpellInfo; - const SpellInfo* spellInfo; - - for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i, ++AIInfo) + sSpellMgr->ForEachSpellInfo([](SpellInfo const* spellInfo) { - spellInfo = sSpellMgr->GetSpellInfo(i); - if (!spellInfo) - continue; + AISpellInfoType* AIInfo = &AISpellInfo[{ spellInfo->Id, spellInfo->Difficulty }]; if (spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD)) AIInfo->condition = AICOND_DIE; @@ -215,7 +212,7 @@ void UnitAI::FillAISpellInfo() UPDATE_TARGET(AITARGET_SELF) else { - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (!effect) continue; @@ -239,7 +236,80 @@ void UnitAI::FillAISpellInfo() } AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime; AIInfo->maxRange = spellInfo->GetMaxRange(false) * 3 / 4; - } + + AIInfo->Effects = 0; + AIInfo->Targets = 0; + + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) + { + if (!effect) + continue; + + // Spell targets self. + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER) + AIInfo->Targets |= 1 << (SELECT_TARGET_SELF - 1); + + // Spell targets a single enemy. + if (effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || + effect->TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY) + AIInfo->Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY - 1); + + // Spell targets AoE at enemy. + if (effect->TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || + effect->TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || + effect->TargetA.GetTarget() == TARGET_SRC_CASTER || + effect->TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) + AIInfo->Targets |= 1 << (SELECT_TARGET_AOE_ENEMY - 1); + + // Spell targets an enemy. + if (effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || + effect->TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY || + effect->TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || + effect->TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || + effect->TargetA.GetTarget() == TARGET_SRC_CASTER || + effect->TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) + AIInfo->Targets |= 1 << (SELECT_TARGET_ANY_ENEMY - 1); + + // Spell targets a single friend (or self). + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER || + effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY || + effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY) + AIInfo->Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND - 1); + + // Spell targets AoE friends. + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY || + effect->TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY || + effect->TargetA.GetTarget() == TARGET_SRC_CASTER) + AIInfo->Targets |= 1 << (SELECT_TARGET_AOE_FRIEND - 1); + + // Spell targets any friend (or self). + if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER || + effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY || + effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY || + effect->TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY || + effect->TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY || + effect->TargetA.GetTarget() == TARGET_SRC_CASTER) + AIInfo->Targets |= 1 << (SELECT_TARGET_ANY_FRIEND - 1); + + // Make sure that this spell includes a damage effect. + if (effect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE || + effect->Effect == SPELL_EFFECT_INSTAKILL || + effect->Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || + effect->Effect == SPELL_EFFECT_HEALTH_LEECH) + AIInfo->Effects |= 1 << (SELECT_EFFECT_DAMAGE - 1); + + // Make sure that this spell includes a healing effect (or an apply aura with a periodic heal). + if (effect->Effect == SPELL_EFFECT_HEAL || + effect->Effect == SPELL_EFFECT_HEAL_MAX_HEALTH || + effect->Effect == SPELL_EFFECT_HEAL_MECHANICAL || + (effect->Effect == SPELL_EFFECT_APPLY_AURA && effect->ApplyAuraName == 8)) + AIInfo->Effects |= 1 << (SELECT_EFFECT_HEALING - 1); + + // Make sure that this spell applies an aura. + if (effect->Effect == SPELL_EFFECT_APPLY_AURA) + AIInfo->Effects |= 1 << (SELECT_EFFECT_AURA - 1); + } + }); } uint32 UnitAI::GetDialogStatus(Player* /*player*/) @@ -287,7 +357,7 @@ bool DefaultTargetSelector::operator()(Unit const* target) const } SpellTargetSelector::SpellTargetSelector(Unit* caster, uint32 spellId) : - _caster(caster), _spellInfo(sSpellMgr->GetSpellInfo(spellId)) + _caster(caster), _spellInfo(sSpellMgr->GetSpellInfo(spellId, caster->GetMap()->GetDifficultyID())) { ASSERT(_spellInfo); } diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index ac5e9165715..508d9e70d70 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -22,6 +22,7 @@ #include "EventMap.h" #include "ObjectGuid.h" #include "ThreatManager.h" +#include <unordered_map> #define CAST_AI(a, b) (dynamic_cast<a*>(b)) #define ENSURE_AI(a,b) (EnsureAI<a>(b)) @@ -40,6 +41,7 @@ class SpellInfo; class Unit; struct AISpellInfoType; enum DamageEffectType : uint8; +enum Difficulty : uint8; enum SpellEffIndex : uint8; //Selection method used by SelectTarget @@ -270,7 +272,7 @@ class TC_GAME_API UnitAI void DoMeleeAttackIfReady(); bool DoSpellAttackIfReady(uint32 spellId); - static AISpellInfoType* AISpellInfo; + static std::unordered_map<std::pair<uint32, Difficulty>, AISpellInfoType> AISpellInfo; static void FillAISpellInfo(); // Called when a player opens a gossip dialog with the creature. diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 3c65160aaf6..80d59e4e7cc 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -17,6 +17,7 @@ #include "CreatureAI.h" #include "AreaBoundary.h" +#include "Containers.h" #include "Creature.h" #include "CreatureAIImpl.h" #include "CreatureTextMgr.h" @@ -41,8 +42,11 @@ void CreatureAI::OnCharmed(bool apply) } } -AISpellInfoType* UnitAI::AISpellInfo; -AISpellInfoType* GetAISpellInfo(uint32 i) { return &UnitAI::AISpellInfo[i]; } +std::unordered_map<std::pair<uint32, Difficulty>, AISpellInfoType> UnitAI::AISpellInfo; +AISpellInfoType* GetAISpellInfo(uint32 spellId, Difficulty difficulty) +{ + return Trinity::Containers::MapGetValuePtr(UnitAI::AISpellInfo, { spellId, difficulty }); +} CreatureAI::CreatureAI(Creature* creature) : UnitAI(creature), me(creature), _boundary(nullptr), _negateBoundary(false), m_MoveInLineOfSight_locked(false) { diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index edc09a650c7..b274a4794d1 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -36,31 +36,6 @@ typedef std::vector<AreaBoundary const*> CreatureBoundary; #define TIME_INTERVAL_LOOK 5000 #define VISIBILITY_RANGE 10000 -//Spell targets used by SelectSpell -enum SelectTargetType -{ - SELECT_TARGET_DONTCARE = 0, //All target types allowed - - SELECT_TARGET_SELF, //Only Self casting - - SELECT_TARGET_SINGLE_ENEMY, //Only Single Enemy - SELECT_TARGET_AOE_ENEMY, //Only AoE Enemy - SELECT_TARGET_ANY_ENEMY, //AoE or Single Enemy - - SELECT_TARGET_SINGLE_FRIEND, //Only Single Friend - SELECT_TARGET_AOE_FRIEND, //Only AoE Friend - SELECT_TARGET_ANY_FRIEND //AoE or Single Friend -}; - -//Spell Effects used by SelectSpell -enum SelectEffect -{ - SELECT_EFFECT_DONTCARE = 0, //All spell effects allowed - SELECT_EFFECT_DAMAGE, //Spell does damage - SELECT_EFFECT_HEALING, //Spell does healing - SELECT_EFFECT_AURA //Spell applies an aura -}; - enum SCEquip { EQUIP_NO_CHANGE = -1, diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h index a14446bf457..cbc7c5912a0 100644 --- a/src/server/game/AI/CreatureAIImpl.h +++ b/src/server/game/AI/CreatureAIImpl.h @@ -22,6 +22,7 @@ #include <functional> class WorldObject; +enum Difficulty : uint8; template<typename First, typename Second, typename... Rest> inline First const& RAND(First const& first, Second const& second, Rest const&... rest) @@ -49,6 +50,31 @@ enum AICondition #define AI_DEFAULT_COOLDOWN 5000 +//Spell targets used by SelectSpell +enum SelectTargetType : uint8 +{ + SELECT_TARGET_DONTCARE = 0, //All target types allowed + + SELECT_TARGET_SELF, //Only Self casting + + SELECT_TARGET_SINGLE_ENEMY, //Only Single Enemy + SELECT_TARGET_AOE_ENEMY, //Only AoE Enemy + SELECT_TARGET_ANY_ENEMY, //AoE or Single Enemy + + SELECT_TARGET_SINGLE_FRIEND, //Only Single Friend + SELECT_TARGET_AOE_FRIEND, //Only AoE Friend + SELECT_TARGET_ANY_FRIEND //AoE or Single Friend +}; + +//Spell Effects used by SelectSpell +enum SelectEffect : uint8 +{ + SELECT_EFFECT_DONTCARE = 0, //All spell effects allowed + SELECT_EFFECT_DAMAGE, //Spell does damage + SELECT_EFFECT_HEALING, //Spell does healing + SELECT_EFFECT_AURA //Spell applies an aura +}; + struct AISpellInfoType { AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT) @@ -58,9 +84,12 @@ struct AISpellInfoType uint32 cooldown; uint32 realCooldown; float maxRange; + + uint8 Targets; // set of enum SelectTarget + uint8 Effects; // set of enum SelectEffect }; -AISpellInfoType* GetAISpellInfo(uint32 i); +AISpellInfoType* GetAISpellInfo(uint32 spellId, Difficulty difficulty); TC_GAME_API bool InstanceHasScript(WorldObject const* obj, char const* scriptName); diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp index 7a7c7b8c0d0..6d5b7060099 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.cpp +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -18,6 +18,7 @@ #include "PlayerAI.h" #include "Creature.h" #include "Item.h" +#include "Map.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "Player.h" @@ -498,7 +499,7 @@ PlayerAI::TargetedSpell PlayerAI::VerifySpellCast(uint32 spellId, Unit* target) if (!knownRank) return {}; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(knownRank); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(knownRank, me->GetMap()->GetDifficultyID()); if (!spellInfo) return {}; diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 59fdee4d181..71125e716a6 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -20,6 +20,7 @@ #include "DB2Stores.h" #include "Cell.h" #include "CellImpl.h" +#include "CreatureAIImpl.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "InstanceScript.h" @@ -30,13 +31,6 @@ #include "SpellMgr.h" #include "TemporarySummon.h" -// Spell summary for ScriptedAI::SelectSpell -struct TSpellSummary -{ - uint8 Targets; // set of enum SelectTarget - uint8 Effects; // set of enum SelectEffect -} extern* SpellSummary; - void SummonList::Summon(Creature const* summon) { storage_.push_back(summon->GetGUID()); @@ -231,23 +225,25 @@ SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mec uint32 spellCount = 0; SpellInfo const* tempSpell = nullptr; + AISpellInfoType const* aiSpell = nullptr; //Check if each spell is viable(set it to null if not) for (uint32 i = 0; i < MAX_CREATURE_SPELLS; i++) { - tempSpell = sSpellMgr->GetSpellInfo(me->m_spells[i]); + tempSpell = sSpellMgr->GetSpellInfo(me->m_spells[i], me->GetMap()->GetDifficultyID()); + aiSpell = GetAISpellInfo(me->m_spells[i], me->GetMap()->GetDifficultyID()); //This spell doesn't exist - if (!tempSpell) + if (!tempSpell || !aiSpell) continue; // Targets and Effects checked first as most used restrictions //Check the spell targets if specified - if (targets && !(SpellSummary[me->m_spells[i]].Targets & (1 << (targets-1)))) + if (targets && !(aiSpell->Targets & (1 << (targets-1)))) continue; //Check the type of spell if we are looking for a specific spell type - if (effect && !(SpellSummary[me->m_spells[i]].Effects & (1 << (effect-1)))) + if (effect && !(aiSpell->Effects & (1 << (effect-1)))) continue; //Check for school if specified diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 53fb97be2aa..bb61dfbaab0 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -24,6 +24,8 @@ #include "TaskScheduler.h" class InstanceScript; +enum SelectTargetType : uint8; +enum SelectEffect : uint8; class TC_GAME_API SummonList { diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 04af075e9af..ebf884133a4 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -656,7 +656,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u // unless target is outside spell range, out of mana, or LOS. bool _allowMove = false; - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(e.action.cast.spell); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(e.action.cast.spell, me->GetMap()->GetDifficultyID()); std::vector<SpellPowerCost> costs = spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()); bool hasPower = true; for (SpellPowerCost const& cost : costs) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 37e40a133bf..7e660acf4a7 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -566,7 +566,7 @@ bool SmartAIMgr::IsGameObjectValid(SmartScriptHolder const& e, uint32 entry) bool SmartAIMgr::IsSpellValid(SmartScriptHolder const& e, uint32 entry) { - if (!sSpellMgr->GetSpellInfo(entry)) + if (!sSpellMgr->GetSpellInfo(entry, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry); return false; @@ -717,7 +717,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_EVENT_SPELLHIT_TARGET: if (e.event.spellHit.spell) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.event.spellHit.spell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.event.spellHit.spell, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); @@ -780,7 +780,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) return false; break; case SMART_EVENT_VICTIM_CASTING: - if (e.event.targetCasting.spellId > 0 && !sSpellMgr->GetSpellInfo(e.event.targetCasting.spellId)) + if (e.event.targetCasting.spellId > 0 && !sSpellMgr->GetSpellInfo(e.event.targetCasting.spellId, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry " SI64FMTD " SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); return false; @@ -1131,8 +1131,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) if (!IsSpellValid(e, e.action.cast.spell)) return false; - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(e.action.cast.spell); - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(e.action.cast.spell, DIFFICULTY_NONE); + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (effect && (effect->IsEffect(SPELL_EFFECT_KILL_CREDIT) || effect->IsEffect(SPELL_EFFECT_KILL_CREDIT2))) { @@ -1650,31 +1650,23 @@ void SmartAIMgr::LoadHelperStores() { uint32 oldMSTime = getMSTime(); - SpellInfo const* spellInfo = NULL; - for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i) + sSpellMgr->ForEachSpellInfo([this](SpellInfo const* spellInfo) { - spellInfo = sSpellMgr->GetSpellInfo(i); - if (!spellInfo) - continue; - - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (!effect) continue; if (effect->IsEffect(SPELL_EFFECT_SUMMON)) - SummonCreatureSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(i, SpellEffIndex(effect->EffectIndex)))); - + SummonCreatureSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(spellInfo->Id, SpellEffIndex(effect->EffectIndex)))); else if (effect->IsEffect(SPELL_EFFECT_SUMMON_OBJECT_WILD)) - SummonGameObjectSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(i, SpellEffIndex(effect->EffectIndex)))); - + SummonGameObjectSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(spellInfo->Id, SpellEffIndex(effect->EffectIndex)))); else if (effect->IsEffect(SPELL_EFFECT_KILL_CREDIT) || effect->IsEffect(SPELL_EFFECT_KILL_CREDIT2)) - KillCreditSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(i, SpellEffIndex(effect->EffectIndex)))); - + KillCreditSpellStore.insert(std::make_pair(uint32(effect->MiscValue), std::make_pair(spellInfo->Id, SpellEffIndex(effect->EffectIndex)))); else if (effect->IsEffect(SPELL_EFFECT_CREATE_ITEM)) - CreateItemSpellStore.insert(std::make_pair(uint32(effect->ItemType), std::make_pair(i, SpellEffIndex(effect->EffectIndex)))); + CreateItemSpellStore.insert(std::make_pair(uint32(effect->ItemType), std::make_pair(spellInfo->Id, SpellEffIndex(effect->EffectIndex)))); } - } + }); TC_LOG_INFO("server.loading", ">> Loaded SmartAIMgr Helpers in %u ms", GetMSTimeDiffToNow(oldMSTime)); } diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index 63e681f2273..ca8a7627527 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -137,14 +137,14 @@ bool CriteriaData::IsValid(Criteria const* criteria) case CRITERIA_DATA_TYPE_S_AURA: case CRITERIA_DATA_TYPE_T_AURA: { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(Aura.SpellId); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(Aura.SpellId, DIFFICULTY_NONE); if (!spellEntry) { TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a wrong spell id in value1 (%u), ignored.", criteria->ID, criteria->Entry->Type, (DataType == CRITERIA_DATA_TYPE_S_AURA ? "CRITERIA_DATA_TYPE_S_AURA" : "CRITERIA_DATA_TYPE_T_AURA"), DataType, Aura.SpellId); return false; } - SpellEffectInfo const* effect = spellEntry->GetEffect(DIFFICULTY_NONE, Aura.EffectIndex); + SpellEffectInfo const* effect = spellEntry->GetEffect(Aura.EffectIndex); if (!effect) { TC_LOG_ERROR("sql.sql", "Table `criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a wrong spell effect index in value2 (%u), ignored.", diff --git a/src/server/game/Chat/ChatLink.cpp b/src/server/game/Chat/ChatLink.cpp index ba2e635c08b..d9f28c0b987 100644 --- a/src/server/game/Chat/ChatLink.cpp +++ b/src/server/game/Chat/ChatLink.cpp @@ -461,7 +461,7 @@ bool SpellChatLink::Initialize(std::istringstream& iss) return false; } // Validate spell - _spell = sSpellMgr->GetSpellInfo(spellId); + _spell = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!_spell) { TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |spell command", iss.str().c_str(), spellId); @@ -594,7 +594,7 @@ bool TradeChatLink::Initialize(std::istringstream& iss) return false; } // Validate spell - _spell = sSpellMgr->GetSpellInfo(spellId); + _spell = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!_spell) { TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", iss.str().c_str(), spellId); @@ -652,7 +652,7 @@ bool TalentChatLink::Initialize(std::istringstream& iss) return false; } // Validate talent's spell - _spell = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + _spell = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE); if (!_spell) { TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", iss.str().c_str(), talentInfo->SpellID); @@ -684,7 +684,7 @@ bool EnchantmentChatLink::Initialize(std::istringstream& iss) return false; } // Validate spell - _spell = sSpellMgr->GetSpellInfo(spellId); + _spell = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!_spell) { TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |enchant command", iss.str().c_str(), spellId); @@ -723,7 +723,7 @@ bool GlyphChatLink::Initialize(std::istringstream& iss) return false; } // Validate glyph's spell - _spell = sSpellMgr->GetSpellInfo(_glyph->SpellID); + _spell = sSpellMgr->GetSpellInfo(_glyph->SpellID, DIFFICULTY_NONE); if (!_spell) { TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |glyph command", iss.str().c_str(), _glyph->SpellID); diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 76503bc6084..f7240308aef 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -40,7 +40,7 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float threat *= threatEntry->pctMod; // Energize is not affected by Mods - for (SpellEffectInfo const* effect : threatSpell->GetEffectsForDifficulty(hatedUnit->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : threatSpell->GetEffects()) if (effect && (effect->Effect == SPELL_EFFECT_ENERGIZE || effect->ApplyAuraName == SPELL_AURA_PERIODIC_ENERGIZE)) return threat; diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index f47af683485..cbc704b38fa 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1357,105 +1357,110 @@ bool ConditionMgr::addToGossipMenuItems(Condition* cond) const bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const { - uint32 conditionEffMask = cond->SourceGroup; - SpellInfo* spellInfo = const_cast<SpellInfo*>(sSpellMgr->AssertSpellInfo(cond->SourceEntry)); - std::list<uint32> sharedMasks; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + bool valid = false; + sSpellMgr->ForEachSpellInfoDifficulty(cond->SourceEntry, [&](SpellInfo const* spellInfo) { - SpellEffectInfo const* effect = spellInfo->GetEffect(DIFFICULTY_NONE, i); - if (!effect) - continue; - - // check if effect is already a part of some shared mask - bool found = false; - for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) + uint32 conditionEffMask = cond->SourceGroup; + std::list<uint32> sharedMasks; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if ((1 << i) & *itr) + SpellEffectInfo const* effect = spellInfo->GetEffect(i); + if (!effect) + continue; + + // check if effect is already a part of some shared mask + bool found = false; + for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) { - found = true; - break; + if ((1 << i) & *itr) + { + found = true; + break; + } } - } - - if (found) - continue; - // build new shared mask with found effect - uint32 sharedMask = 1 << i; - ConditionContainer* cmp = effect->ImplicitTargetConditions; - for (uint8 effIndex = i + 1; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - { - SpellEffectInfo const* inner = spellInfo->GetEffect(DIFFICULTY_NONE, effIndex); - if (!inner) + if (found) continue; - if (inner->ImplicitTargetConditions == cmp) - sharedMask |= 1 << effIndex; - } + // build new shared mask with found effect + uint32 sharedMask = 1 << i; + ConditionContainer* cmp = effect->ImplicitTargetConditions; + for (uint8 effIndex = i + 1; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + { + SpellEffectInfo const* inner = spellInfo->GetEffect(effIndex); + if (!inner) + continue; - sharedMasks.push_back(sharedMask); - } + if (inner->ImplicitTargetConditions == cmp) + sharedMask |= 1 << effIndex; + } - for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) - { - // some effect indexes should have same data - if (uint32 commonMask = *itr & conditionEffMask) + sharedMasks.push_back(sharedMask); + } + + for (std::list<uint32>::iterator itr = sharedMasks.begin(); itr != sharedMasks.end(); ++itr) { - uint8 firstEffIndex = 0; - for (; firstEffIndex < MAX_SPELL_EFFECTS; ++firstEffIndex) - if ((1<<firstEffIndex) & *itr) - break; + // some effect indexes should have same data + if (uint32 commonMask = *itr & conditionEffMask) + { + uint8 firstEffIndex = 0; + for (; firstEffIndex < MAX_SPELL_EFFECTS; ++firstEffIndex) + if ((1 << firstEffIndex) & *itr) + break; - if (firstEffIndex >= MAX_SPELL_EFFECTS) - return false; + if (firstEffIndex >= MAX_SPELL_EFFECTS) + return; - SpellEffectInfo const* effect = spellInfo->GetEffect(DIFFICULTY_NONE, firstEffIndex); - if (!effect) - continue; + SpellEffectInfo const* effect = spellInfo->GetEffect(firstEffIndex); + if (!effect) + continue; - // get shared data - ConditionContainer* sharedList = effect->ImplicitTargetConditions; + // get shared data + ConditionContainer* sharedList = effect->ImplicitTargetConditions; - // there's already data entry for that sharedMask - if (sharedList) - { - // we have overlapping masks in db - if (conditionEffMask != *itr) + // there's already data entry for that sharedMask + if (sharedList) { - TC_LOG_ERROR("sql.sql", "%s in `condition` table, has incorrect SourceGroup %u (spell effectMask) set - " - "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring.", cond->ToString().c_str(), cond->SourceGroup); - return false; + // we have overlapping masks in db + if (conditionEffMask != *itr) + { + TC_LOG_ERROR("sql.sql", "%s in `condition` table, has incorrect SourceGroup %u (spell effectMask) set - " + "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring (Difficulty %u).", + cond->ToString().c_str(), cond->SourceGroup, uint32(spellInfo->Difficulty)); + return; + } } - } - // no data for shared mask, we can create new submask - else - { - // add new list, create new shared mask - sharedList = new ConditionContainer(); - bool assigned = false; - for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i) + // no data for shared mask, we can create new submask + else { - SpellEffectInfo const* eff = spellInfo->GetEffect(DIFFICULTY_NONE, i); - if (!eff) - continue; - - if ((1 << i) & commonMask) + // add new list, create new shared mask + sharedList = new ConditionContainer(); + bool assigned = false; + for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i) { - const_cast<SpellEffectInfo*>(eff)->ImplicitTargetConditions = sharedList; - assigned = true; + SpellEffectInfo const* eff = spellInfo->GetEffect(i); + if (!eff) + continue; + + if ((1 << i) & commonMask) + { + const_cast<SpellEffectInfo*>(eff)->ImplicitTargetConditions = sharedList; + assigned = true; + } } - } - if (!assigned) - { - delete sharedList; - break; + if (!assigned) + { + delete sharedList; + break; + } } + sharedList->push_back(cond); + break; } - sharedList->push_back(cond); - break; } - } + valid = true; + }); return true; } @@ -1711,7 +1716,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const } case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table does not exist in `spell.dbc`, ignoring.", cond->ToString().c_str()); @@ -1731,7 +1736,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const if (!((1 << i) & cond->SourceGroup)) continue; - SpellEffectInfo const* effect = spellInfo->GetEffect(DIFFICULTY_NONE, i); + SpellEffectInfo const* effect = spellInfo->GetEffect(i); if (!effect) continue; @@ -1780,7 +1785,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const case CONDITION_SOURCE_TYPE_SPELL: case CONDITION_SOURCE_TYPE_SPELL_PROC: { - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry); + SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE); if (!spellProto) { TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table does not exist in `spell.dbc`, ignoring.", cond->ToString().c_str()); @@ -1802,7 +1807,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const return false; } - if (!sSpellMgr->GetSpellInfo(cond->SourceEntry)) + if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table does not exist in `spell.dbc`, ignoring.", cond->ToString().c_str()); return false; @@ -1815,7 +1820,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const return false; } - if (!sSpellMgr->GetSpellInfo(cond->SourceEntry)) + if (!sSpellMgr->GetSpellInfo(cond->SourceEntry, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table does not exist in `spell.dbc`, ignoring.", cond->ToString().c_str()); return false; @@ -1879,7 +1884,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const { case CONDITION_AURA: { - if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1)) + if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "%s has non existing spell (Id: %d), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); return false; @@ -2048,7 +2053,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const } case CONDITION_SPELL: { - if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1)) + if (!sSpellMgr->GetSpellInfo(cond->ConditionValue1, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "%s has non existing spell (Id: %d), skipped", cond->ToString(true).c_str(), cond->ConditionValue1); return false; diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index 20c7f95a016..8b21de0197d 100644 --- a/src/server/game/Conditions/DisableMgr.cpp +++ b/src/server/game/Conditions/DisableMgr.cpp @@ -94,7 +94,7 @@ void LoadDisables() switch (type) { case DISABLE_TYPE_SPELL: - if (!(sSpellMgr->GetSpellInfo(entry) || flags & SPELL_DISABLE_DEPRECATED_SPELL)) + if (!(sSpellMgr->GetSpellInfo(entry, DIFFICULTY_NONE) || flags & SPELL_DISABLE_DEPRECATED_SPELL)) { TC_LOG_ERROR("sql.sql", "Spell entry %u from `disables` doesn't exist in dbc, skipped.", entry); continue; diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 54231bead60..aa758b408dd 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -421,8 +421,6 @@ namespace SpecializationSpellsContainer _specializationSpellsBySpec; std::unordered_set<std::pair<int32, uint32>> _specsBySpecSet; std::unordered_set<uint8> _spellFamilyNames; - SpellPowerContainer _spellPowers; - SpellPowerDifficultyContainer _spellPowerDifficulties; SpellProcsPerMinuteModContainer _spellProcsPerMinuteMods; TalentsByPosition _talentsByPosition; ToyItemIdsContainer _toys; @@ -1139,26 +1137,6 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) for (SpellClassOptionsEntry const* classOption : sSpellClassOptionsStore) _spellFamilyNames.insert(classOption->SpellClassSet); - for (SpellPowerEntry const* power : sSpellPowerStore) - { - if (SpellPowerDifficultyEntry const* powerDifficulty = sSpellPowerDifficultyStore.LookupEntry(power->ID)) - { - std::vector<SpellPowerEntry const*>& powers = _spellPowerDifficulties[power->SpellID][powerDifficulty->DifficultyID]; - if (powers.size() <= powerDifficulty->OrderIndex) - powers.resize(powerDifficulty->OrderIndex + 1); - - powers[powerDifficulty->OrderIndex] = power; - } - else - { - std::vector<SpellPowerEntry const*>& powers = _spellPowers[power->SpellID]; - if (powers.size() <= power->OrderIndex) - powers.resize(power->OrderIndex + 1); - - powers[power->OrderIndex] = power; - } - } - for (SpellProcsPerMinuteModEntry const* ppmMod : sSpellProcsPerMinuteModStore) _spellProcsPerMinuteMods[ppmMod->SpellProcsPerMinuteID].push_back(ppmMod); @@ -2626,48 +2604,6 @@ 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; - - auto difficultyItr = _spellPowerDifficulties.find(spellId); - if (difficultyItr != _spellPowerDifficulties.end()) - { - if (hasDifficultyPowers) - *hasDifficultyPowers = true; - - DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty); - while (difficultyEntry) - { - auto powerDifficultyItr = difficultyItr->second.find(difficultyEntry->ID); - if (powerDifficultyItr != difficultyItr->second.end()) - { - if (powerDifficultyItr->second.size() > powers.size()) - powers.resize(powerDifficultyItr->second.size()); - - for (SpellPowerEntry const* difficultyPower : powerDifficultyItr->second) - if (!powers[difficultyPower->OrderIndex]) - powers[difficultyPower->OrderIndex] = difficultyPower; - } - - difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID); - } - } - - auto itr = _spellPowers.find(spellId); - if (itr != _spellPowers.end()) - { - if (itr->second.size() > powers.size()) - powers.resize(itr->second.size()); - - for (SpellPowerEntry const* power : itr->second) - if (!powers[power->OrderIndex]) - powers[power->OrderIndex] = power; - } - - return powers; -} - std::vector<SpellProcsPerMinuteModEntry const*> DB2Manager::GetSpellProcsPerMinuteMods(uint32 spellprocsPerMinuteId) const { auto itr = _spellProcsPerMinuteMods.find(spellprocsPerMinuteId); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index cc508a8883f..843b1b0479f 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -190,6 +190,7 @@ TC_GAME_API extern DB2Storage<SpellLevelsEntry> sSpellLevels TC_GAME_API extern DB2Storage<SpellMiscEntry> sSpellMiscStore; TC_GAME_API extern DB2Storage<SpellNameEntry> sSpellNameStore; TC_GAME_API extern DB2Storage<SpellPowerEntry> sSpellPowerStore; +TC_GAME_API extern DB2Storage<SpellPowerDifficultyEntry> sSpellPowerDifficultyStore; TC_GAME_API extern DB2Storage<SpellProcsPerMinuteEntry> sSpellProcsPerMinuteStore; TC_GAME_API extern DB2Storage<SpellRadiusEntry> sSpellRadiusStore; TC_GAME_API extern DB2Storage<SpellRangeEntry> sSpellRangeStore; @@ -358,7 +359,6 @@ public: std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId) const; bool IsSpecSetMember(int32 specSetId, 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; static bool IsTotemCategoryCompatibleWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId); diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 92dcaa236bc..dac3557f501 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -1263,6 +1263,8 @@ enum SpellProcsPerMinuteModType SPELL_PPM_MOD_BATTLEGROUND = 7 }; +constexpr std::size_t MAX_POWERS_PER_SPELL = 4; + enum SpellShapeshiftFormFlags { SHAPESHIFT_FORM_IS_NOT_A_SHAPESHIFT = 0x0001, diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index c5621e86986..b1c386d2e51 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -552,11 +552,11 @@ bool UnitFitToActionRequirement(Unit* unit, Unit* caster, AreaTriggerAction cons { case AREATRIGGER_ACTION_USER_FRIEND: { - return caster->_IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param)); + return caster->_IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID())); } case AREATRIGGER_ACTION_USER_ENEMY: { - return caster->_IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param)); + return caster->_IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID())); } case AREATRIGGER_ACTION_USER_RAID: { diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 1f124d16ed1..2d66f88a745 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2109,7 +2109,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const return false; bool immunedToAllEffects = true; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (!effect || !effect->IsEffect()) continue; @@ -2129,7 +2129,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const { - SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficultyID(), index); + SpellEffectInfo const* effect = spellInfo->GetEffect(index); if (!effect) return true; @@ -2165,7 +2165,7 @@ SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) { if (!m_spells[i]) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(m_spells[i]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(m_spells[i], GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("entities.unit", "WORLD: unknown spell id %i", m_spells[i]); @@ -2173,7 +2173,7 @@ SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) } bool bcontinue = true; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (effect && ((effect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE) || (effect->Effect == SPELL_EFFECT_INSTAKILL) || @@ -2217,7 +2217,7 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim) { if (!m_spells[i]) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(m_spells[i]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(m_spells[i], GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("entities.unit", "WORLD: unknown spell id %i", m_spells[i]); @@ -2225,7 +2225,7 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim) } bool bcontinue = true; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (effect && (effect->Effect == SPELL_EFFECT_HEAL)) { @@ -2567,7 +2567,7 @@ bool Creature::LoadCreaturesAddon() { for (std::vector<uint32>::const_iterator itr = cainfo->auras.begin(); itr != cainfo->auras.end(); ++itr) { - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(*itr); + SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(*itr, GetMap()->GetDifficultyID()); if (!AdditionalSpellInfo) { TC_LOG_ERROR("sql.sql", "Creature (%s) has wrong spell %u defined in `auras` field.", GetGUID().ToString().c_str(), *itr); @@ -2931,7 +2931,7 @@ float Creature::GetPetChaseDistance() const if (!spellID) continue; - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID, GetMap()->GetDifficultyID())) { if (spellInfo->GetRecoveryTime() == 0 && // No cooldown spellInfo->RangeEntry->ID != 1 /*Self*/ && spellInfo->RangeEntry->ID != 2 /*Combat Range*/ && @@ -3100,7 +3100,7 @@ void Creature::FocusTarget(Spell const* focusSpell, WorldObject const* target) SpellInfo const* spellInfo = focusSpell->GetSpellInfo(); // don't use spell focus for vehicle spells - if (spellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_CONTROL_VEHICLE)) + if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) return; if ((!target || target == this) && !focusSpell->GetCastTime()) // instant cast, untargeted (or self-targeted) spell doesn't need any facing updates diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 76be982fdb2..8dc0ea6e352 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -450,19 +450,10 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU packet.SuggestedPartyMembers = quest->GetSuggestedPlayers(); // RewardSpell can teach multiple spells in trigger spell effects. But not all effects must be SPELL_EFFECT_LEARN_SPELL. See example spell 33950 - if (quest->GetRewSpell()) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpell()); - if (spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL)) - { - SpellEffectInfoVector effects = spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE); - for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) - { - if ((*itr)->IsEffect(SPELL_EFFECT_LEARN_SPELL)) - packet.LearnSpells.push_back((*itr)->TriggerSpell); - } - } - } + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpell(), DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) + if (effect->IsEffect(SPELL_EFFECT_LEARN_SPELL)) + packet.LearnSpells.push_back(effect->TriggerSpell); quest->BuildQuestRewards(packet.Rewards, _session->GetPlayer()); diff --git a/src/server/game/Entities/Creature/Trainer.cpp b/src/server/game/Entities/Creature/Trainer.cpp index db1c0a528b6..bfdf21a06bd 100644 --- a/src/server/game/Entities/Creature/Trainer.cpp +++ b/src/server/game/Entities/Creature/Trainer.cpp @@ -26,7 +26,7 @@ namespace Trainer { bool Spell::IsCastable() const { - return sSpellMgr->AssertSpellInfo(SpellId)->HasEffect(SPELL_EFFECT_LEARN_SPELL); + return sSpellMgr->AssertSpellInfo(SpellId, DIFFICULTY_NONE)->HasEffect(SPELL_EFFECT_LEARN_SPELL); } Trainer::Trainer(uint32 id, Type type, std::string greeting, std::vector<Spell> spells) : _id(id), _type(type), _spells(std::move(spells)) @@ -111,7 +111,7 @@ namespace Trainer if (state != SpellState::Available) return false; - SpellInfo const* trainerSpellInfo = sSpellMgr->AssertSpellInfo(trainerSpell->SpellId); + SpellInfo const* trainerSpellInfo = sSpellMgr->AssertSpellInfo(trainerSpell->SpellId, DIFFICULTY_NONE); if (trainerSpellInfo->IsPrimaryProfessionFirstRank() && !player->GetFreePrimaryProfessionPoints()) return false; @@ -142,7 +142,7 @@ namespace Trainer // check ranks bool hasLearnSpellEffect = false; bool knowsAllLearnedSpells = true; - for (SpellEffectInfo const* spellEffect : sSpellMgr->AssertSpellInfo(trainerSpell->SpellId)->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* spellEffect : sSpellMgr->AssertSpellInfo(trainerSpell->SpellId, DIFFICULTY_NONE)->GetEffects()) { if (!spellEffect || !spellEffect->IsEffect(SPELL_EFFECT_LEARN_SPELL)) continue; diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index 58e277f61f8..6d74efec87d 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -243,7 +243,7 @@ void DynamicObject::UnbindFromCaster() SpellInfo const* DynamicObject::GetSpellInfo() const { - return sSpellMgr->GetSpellInfo(GetSpellId()); + return sSpellMgr->GetSpellInfo(GetSpellId(), GetMap()->GetDifficultyID()); } void DynamicObject::BuildValuesCreate(ByteBuffer* data, Player const* target) const diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 8cb05644006..4059e6e72d6 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1331,7 +1331,7 @@ void GameObject::TriggeringLinkedGameObject(uint32 trapEntry, Unit* target) if (!trapInfo || trapInfo->type != GAMEOBJECT_TYPE_TRAP) return; - SpellInfo const* trapSpell = sSpellMgr->GetSpellInfo(trapInfo->trap.spell); + SpellInfo const* trapSpell = sSpellMgr->GetSpellInfo(trapInfo->trap.spell, GetMap()->GetDifficultyID()); if (!trapSpell) // checked at load already return; @@ -2053,7 +2053,7 @@ void GameObject::Use(Unit* user) if (!spellId) return; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) { if (user->GetTypeId() != TYPEID_PLAYER || !sOutdoorPvPMgr->HandleCustomSpell(user->ToPlayer(), spellId, this)) @@ -2079,12 +2079,12 @@ void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /* = tru void GameObject::CastSpell(Unit* target, uint32 spellId, TriggerCastFlags triggered) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) return; bool self = false; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (effect && effect->TargetA.GetTarget() == TARGET_UNIT_CASTER) { diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index abe8914e48a..41fcbf6b32e 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -119,7 +119,7 @@ void AddItemsSetItem(Player* player, Item* item) if (eff->SetBonuses.count(itemSetSpell)) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemSetSpell->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("entities.player.items", "WORLD: unknown spell id %u in items set %u effects", itemSetSpell->SpellID, setid); @@ -174,7 +174,7 @@ void RemoveItemsSetItem(Player* player, ItemTemplate const* proto) if (!eff->SetBonuses.count(itemSetSpell)) continue; - player->ApplyEquipSpell(sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID), nullptr, false); + player->ApplyEquipSpell(sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE), nullptr, false); eff->SetBonuses.erase(itemSetSpell); } } diff --git a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h index 1901e5e623d..834321320ef 100644 --- a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h +++ b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h @@ -115,8 +115,8 @@ public: CreatureTemplate const* cinfo = unit->ToCreature()->GetCreatureTemplate(); // this also applies for transform auras - if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(unit->getTransForm())) - for (SpellEffectInfo const* effect : transform->GetEffectsForDifficulty(unit->GetMap()->GetDifficultyID())) + if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(unit->getTransForm(), unit->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : transform->GetEffects()) if (effect && effect->IsAura(SPELL_AURA_TRANSFORM)) if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(effect->MiscValue)) { diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index f6f62c98247..bb6d87b2072 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -157,7 +157,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c return false; uint32 summonSpellId = fields[14].GetUInt32(); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summonSpellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summonSpellId, owner->GetMap()->GetDifficultyID()); bool isTemporarySummon = spellInfo && spellInfo->GetDuration() > 0; if (current && isTemporarySummon) @@ -1167,8 +1167,8 @@ void Pet::_LoadAuras(uint32 timediff) stmt->setUInt32(0, m_charmInfo->GetPetNumber()); /* - 0 1 2 3 4 5 6 7 - SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ? + 0 1 2 3 4 5 6 7 8 + SELECT casterGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ? */ if (PreparedQueryResult auraResult = CharacterDatabase.Query(stmt)) { @@ -1182,15 +1182,22 @@ void Pet::_LoadAuras(uint32 timediff) AuraKey key{ casterGuid, itemGuid, fields[1].GetUInt32(), fields[2].GetUInt32() }; uint32 recalculateMask = fields[3].GetUInt32(); - uint8 stackCount = fields[4].GetUInt8(); - int32 maxDuration = fields[5].GetInt32(); - int32 remainTime = fields[6].GetInt32(); - uint8 remainCharges = fields[7].GetUInt8(); + Difficulty difficulty = Difficulty(fields[4].GetUInt8()); + uint8 stackCount = fields[5].GetUInt8(); + int32 maxDuration = fields[6].GetInt32(); + int32 remainTime = fields[7].GetInt32(); + uint8 remainCharges = fields[8].GetUInt8(); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(key.SpellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(key.SpellId, difficulty); if (!spellInfo) { - TC_LOG_ERROR("entities.pet", "Unknown aura (spellid %u), ignore.", key.SpellId); + TC_LOG_ERROR("entities.pet", "Pet::_LoadAuras: Unknown aura (spellid %u), ignore.", key.SpellId); + continue; + } + + if (difficulty != DIFFICULTY_NONE && !sDifficultyStore.LookupEntry(difficulty)) + { + TC_LOG_ERROR("entities.pet", "Pet::_LoadAuras: Unknown difficulty %u (spellid %u), ignore.", uint32(difficulty), key.SpellId); continue; } @@ -1216,7 +1223,7 @@ void Pet::_LoadAuras(uint32 timediff) AuraLoadEffectInfo& info = effectInfo[key]; ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellInfo->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()); - if (Aura* aura = Aura::TryCreate(spellInfo, castId, key.EffectMask, this, NULL, info.BaseAmounts.data(), NULL, casterGuid)) + if (Aura* aura = Aura::TryCreate(spellInfo, castId, key.EffectMask, this, NULL, difficulty, info.BaseAmounts.data(), NULL, casterGuid)) { if (!aura->CanBeSaved()) { @@ -1265,6 +1272,7 @@ void Pet::_SaveAuras(CharacterDatabaseTransaction& trans) stmt->setUInt32(index++, key.SpellId); stmt->setUInt32(index++, key.EffectMask); stmt->setUInt32(index++, recalculateMask); + stmt->setUInt8(index++, aura->GetCastDifficulty()); stmt->setUInt8(index++, aura->GetStackAmount()); stmt->setInt32(index++, aura->GetMaxDuration()); stmt->setInt32(index++, aura->GetDuration()); @@ -1292,7 +1300,7 @@ void Pet::_SaveAuras(CharacterDatabaseTransaction& trans) bool Pet::addSpell(uint32 spellId, ActiveStates active /*= ACT_DECIDE*/, PetSpellState state /*= PETSPELL_NEW*/, PetSpellType type /*= PETSPELL_NORMAL*/) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!spellInfo) { // do pet spell book cleanup @@ -1358,7 +1366,7 @@ bool Pet::addSpell(uint32 spellId, ActiveStates active /*= ACT_DECIDE*/, PetSpel if (itr2->second.state == PETSPELL_REMOVED) continue; - SpellInfo const* oldRankSpellInfo = sSpellMgr->GetSpellInfo(itr2->first); + SpellInfo const* oldRankSpellInfo = sSpellMgr->GetSpellInfo(itr2->first, DIFFICULTY_NONE); if (!oldRankSpellInfo) continue; @@ -1451,7 +1459,7 @@ void Pet::InitLevelupSpellsForLevel() { for (uint8 i = 0; i < MAX_CREATURE_SPELL_DATA_SLOT; ++i) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(defSpells->spellid[i]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(defSpells->spellid[i], DIFFICULTY_NONE); if (!spellInfo) continue; @@ -1540,7 +1548,7 @@ void Pet::CleanupActionBar() m_charmInfo->SetActionBar(i, 0, ACT_PASSIVE); else if (ab->GetType() == ACT_ENABLED) { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ab->GetAction())) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ab->GetAction(), DIFFICULTY_NONE)) ToggleAutocast(spellInfo, true); } } @@ -1782,7 +1790,7 @@ void Pet::LearnSpecializationSpells() for (size_t j = 0; j < specSpells->size(); ++j) { SpecializationSpellsEntry const* specSpell = specSpells->at(j); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID, DIFFICULTY_NONE); if (!spellInfo || spellInfo->SpellLevel > getLevel()) continue; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 597628b6f4c..5ac0bbb1bc8 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1778,7 +1778,7 @@ void Player::SetObjectScale(float scale) bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const { - SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficultyID(), index); + SpellEffectInfo const* effect = spellInfo->GetEffect(index); if (!effect || !effect->IsEffect()) return false; @@ -2800,7 +2800,7 @@ void DeleteSpellFromAllPlayers(uint32 spellId) bool Player::AddTalent(TalentEntry const* talent, uint8 spec, bool learning) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: %u) does not exist.", talent->SpellID); @@ -2827,14 +2827,14 @@ bool Player::AddTalent(TalentEntry const* talent, uint8 spec, bool learning) void Player::RemoveTalent(TalentEntry const* talent) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID, DIFFICULTY_NONE); if (!spellInfo) return; RemoveSpell(talent->SpellID, true); // search for spells that the talent teaches and unlearn them - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL) RemoveSpell(effect->TriggerSpell, true); @@ -2849,7 +2849,7 @@ void Player::RemoveTalent(TalentEntry const* talent) bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, int32 fromSkill /*= 0*/) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!spellInfo) { // do character spell book cleanup (all characters) @@ -3015,7 +3015,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent if (itr2->second->state == PLAYERSPELL_REMOVED) continue; - SpellInfo const* i_spellInfo = sSpellMgr->GetSpellInfo(itr2->first); + SpellInfo const* i_spellInfo = sSpellMgr->GetSpellInfo(itr2->first, DIFFICULTY_NONE); if (!i_spellInfo) continue; @@ -3212,7 +3212,7 @@ bool Player::HandlePassiveSpellLearn(SpellInfo const* spellInfo) // passive spells which apply aura and have an item requirement are to be added manually, instead of casted if (spellInfo->EquippedItemClass >= 0) { - for (SpellEffectInfo const* effectInfo : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effectInfo : spellInfo->GetEffects()) if (effectInfo && effectInfo->IsAura()) { if (!HasAura(spellInfo->Id) && HasItemFitToSpellRequirements(spellInfo)) @@ -3283,7 +3283,7 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled /*= false*/, bool learn_ // unlearn non talent higher ranks (recursive) if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id)) { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(nextSpell); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(nextSpell, DIFFICULTY_NONE); if (HasSpell(nextSpell) && !spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT)) RemoveSpell(nextSpell, disabled, false); } @@ -3325,7 +3325,7 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled /*= false*/, bool learn_ RemovePetAura(petSpell); // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning) - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, DIFFICULTY_NONE); if (spellInfo && spellInfo->IsPrimaryProfessionFirstRank()) { uint32 freeProfs = GetFreePrimaryProfessionPoints()+1; @@ -3449,7 +3449,7 @@ void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns) // remove cooldowns on spells that have < 10 min CD GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, DIFFICULTY_NONE); return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS; }, true); @@ -5442,7 +5442,7 @@ bool Player::UpdateCraftSkill(uint32 spellid) uint32 SkillValue = GetPureSkillValue(_spell_idx->second->SkillupSkillLineID); // Alchemy Discoveries here - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spellid); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spellid, DIFFICULTY_NONE); if (spellEntry && spellEntry->Mechanic == MECHANIC_DISCOVERY) { if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->SkillupSkillLineID, spellid, this)) @@ -6026,7 +6026,7 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) co switch (type) { case ACTION_BUTTON_SPELL: - if (!sSpellMgr->GetSpellInfo(action)) + if (!sSpellMgr->GetSpellInfo(action, DIFFICULTY_NONE)) { TC_LOG_DEBUG("entities.player", "Player::IsActionButtonDataValid: Spell action %u not added into button %u for player %s (%s): spell does not exist. This can be due to a character imported from a different expansion", action, button, GetName().c_str(), GetGUID().ToString().c_str()); @@ -7918,7 +7918,7 @@ void Player::ApplyItemDependentAuras(Item* item, bool apply) if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE); if (!spellInfo || !spellInfo->IsPassive() || spellInfo->EquippedItemClass < 0) continue; @@ -7955,11 +7955,11 @@ void Player::ApplyItemEquipSpell(Item* item, bool apply, bool formChange /*= fal continue; // check if it is valid spell - SpellInfo const* spellproto = sSpellMgr->GetSpellInfo(effectData->SpellID); + SpellInfo const* spellproto = sSpellMgr->GetSpellInfo(effectData->SpellID, DIFFICULTY_NONE); if (!spellproto) continue; - if (spellproto->HasAura(GetMap()->GetDifficultyID(), SPELL_AURA_MOD_XP_PCT) + if (spellproto->HasAura(SPELL_AURA_MOD_XP_PCT) && !GetSession()->GetCollectionMgr()->CanApplyHeirloomXpBonus(item->GetEntry(), getLevel()) && sDB2Manager.GetHeirloomByItemId(item->GetEntry())) continue; @@ -8033,7 +8033,7 @@ void Player::UpdateItemSetAuras(bool formChange /*= false*/) for (ItemSetSpellEntry const* itemSetSpell : eff->SetBonuses) { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE); if (itemSetSpell->ChrSpecID && itemSetSpell->ChrSpecID != GetPrimarySpecialization()) ApplyEquipSpell(spellInfo, nullptr, false, false); // item set aura is not for current spec @@ -8074,7 +8074,7 @@ void Player::ApplyArtifactPowers(Item* item, bool apply) void Player::ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const* artifactPowerRank, bool apply) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(artifactPowerRank->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(artifactPowerRank->SpellID, DIFFICULTY_NONE); if (!spellInfo) return; @@ -8189,7 +8189,7 @@ void Player::ApplyAzeriteEssence(AzeriteItem* item, uint32 azeriteEssenceId, uin void Player::ApplyAzeriteEssencePower(AzeriteItem* item, AzeriteEssencePowerEntry const* azeriteEssencePower, bool major, bool apply) { - if (SpellInfo const* powerSpell = sSpellMgr->GetSpellInfo(azeriteEssencePower->MinorPowerDescription)) + if (SpellInfo const* powerSpell = sSpellMgr->GetSpellInfo(azeriteEssencePower->MinorPowerDescription, DIFFICULTY_NONE)) { if (apply) CastSpell(this, powerSpell, true, item); @@ -8199,7 +8199,7 @@ void Player::ApplyAzeriteEssencePower(AzeriteItem* item, AzeriteEssencePowerEntr if (major) { - if (SpellInfo const* powerSpell = sSpellMgr->GetSpellInfo(azeriteEssencePower->MajorPowerDescription)) + if (SpellInfo const* powerSpell = sSpellMgr->GetSpellInfo(azeriteEssencePower->MajorPowerDescription, DIFFICULTY_NONE)) { if (powerSpell->IsPassive()) { @@ -8293,7 +8293,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT if (effectData->TriggerType != ITEM_SPELLTRIGGER_CHANCE_ON_HIT) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectData->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectData->SpellID, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("entities.player.items", "Player::CastItemCombatSpell: Player '%s' (%s) cast unknown item spell (ID: %i)", @@ -8302,7 +8302,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT } // not allow proc extra attack spell at extra attack - if (m_extraAttacks && spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + if (m_extraAttacks && spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) return; float chance = (float)spellInfo->ProcChance; @@ -8352,7 +8352,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT if (entry && (entry->AttributesMask & ENCHANT_PROC_ATTR_WHITE_HIT) && damageInfo.GetSpellInfo()) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->EffectArg[s]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->EffectArg[s], DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("entities.player.items", "Player::CastItemCombatSpell: Player '%s' (%s) cast unknown spell (EnchantID: %u, SpellID: %i), ignoring", @@ -8400,8 +8400,8 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - if (spellInfo->GetEffect(DIFFICULTY_NONE, i)->IsEffect()) - values.AddSpellMod(static_cast<SpellValueMod>(SPELLVALUE_BASE_POINT0 + i), CalculatePct(spellInfo->GetEffect(DIFFICULTY_NONE, i)->CalcValue(this), effectPct)); + if (spellInfo->GetEffect(i)->IsEffect()) + values.AddSpellMod(static_cast<SpellValueMod>(SPELLVALUE_BASE_POINT0 + i), CalculatePct(spellInfo->GetEffect(i)->CalcValue(this), effectPct)); } } @@ -8421,7 +8421,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, Objec uint32 learn_spell_id = item->GetEffect(0)->SpellID; uint32 learning_spell_id = item->GetEffect(1)->SpellID; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learn_spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learn_spell_id, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring", item->GetEntry(), learn_spell_id); @@ -8451,7 +8451,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, Objec if (effectData->TriggerType != ITEM_SPELLTRIGGER_ON_USE) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectData->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectData->SpellID, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring", item->GetEntry(), effectData->SpellID); @@ -8485,7 +8485,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, Objec if (pEnchant->Effect[s] != ITEM_ENCHANTMENT_TYPE_USE_SPELL) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->EffectArg[s]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->EffectArg[s], DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Enchant %i, cast unknown spell %i", enchant_id, pEnchant->EffectArg[s]); @@ -12383,7 +12383,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) if (pProto && IsInCombat() && (pProto->GetClass() == ITEM_CLASS_WEAPON || pProto->GetInventoryType() == INVTYPE_RELIC) && m_weaponChangeTimer == 0) { uint32 cooldownSpell = getClass() == CLASS_ROGUE ? 6123 : 6119; - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell); + SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell, DIFFICULTY_NONE); if (!spellProto) TC_LOG_ERROR("entities.player", "Player::EquipItem: Weapon switch cooldown spell %u for player '%s' (%s) couldn't be found in Spell.dbc", @@ -15573,13 +15573,13 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) if (quest->GetSrcSpell() > 0) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetSrcSpell()); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetSrcSpell(), GetMap()->GetDifficultyID()); Unit* caster = this; if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_ON_ACCEPT) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER) && !spellInfo->HasTargetType(TARGET_DEST_CASTER_SUMMON)) if (Unit* unit = questGiver->ToUnit()) - unit->CastSpell(this, quest->GetSrcSpell(), true); + caster = unit; - caster->CastSpell(this, quest->GetSrcSpell(), true); + caster->CastSpell(this, spellInfo, true); } SetQuestSlot(log_slot, quest_id, qtime); @@ -15892,13 +15892,13 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, // cast spells after mark quest complete (some spells have quest completed state requirements in spell_area data) if (quest->GetRewSpell() > 0) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpell()); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpell(), GetMap()->GetDifficultyID()); Unit* caster = this; if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_ON_COMPLETE) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER)) if (Unit* unit = questGiver->ToUnit()) caster = unit; - caster->CastSpell(this, quest->GetRewSpell(), true); + caster->CastSpell(this, spellInfo, true); } else { @@ -15906,13 +15906,13 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, { if (quest->RewardDisplaySpell[i] > 0) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->RewardDisplaySpell[i]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->RewardDisplaySpell[i], GetMap()->GetDifficultyID()); Unit* caster = this; if (questGiver && questGiver->isType(TYPEMASK_UNIT) && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_ON_COMPLETE) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER)) if (Unit * unit = questGiver->ToUnit()) caster = unit; - caster->CastSpell(this, quest->RewardDisplaySpell[i], true); + caster->CastSpell(this, spellInfo, true); } } } @@ -18823,8 +18823,8 @@ void Player::_LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effe } /* - 0 1 2 3 4 5 6 7 8 9 10 - SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel FROM character_aura WHERE guid = ? + 0 1 2 3 4 5 6 7 8 9 10 11 + SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel FROM character_aura WHERE guid = ? */ if (auraResult) { @@ -18835,14 +18835,15 @@ void Player::_LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effe itemGuid.SetRawValue(fields[1].GetBinary()); AuraKey key{ casterGuid, itemGuid, fields[2].GetUInt32(), fields[3].GetUInt32() }; uint32 recalculateMask = fields[4].GetUInt32(); - uint8 stackCount = fields[5].GetUInt8(); - int32 maxDuration = fields[6].GetInt32(); - int32 remainTime = fields[7].GetInt32(); - uint8 remainCharges = fields[8].GetUInt8(); - uint32 castItemId = fields[9].GetUInt32(); - int32 castItemLevel = fields[10].GetInt32(); - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(key.SpellId); + Difficulty difficulty = Difficulty(fields[5].GetUInt8()); + uint8 stackCount = fields[6].GetUInt8(); + int32 maxDuration = fields[7].GetInt32(); + int32 remainTime = fields[8].GetInt32(); + uint8 remainCharges = fields[9].GetUInt8(); + uint32 castItemId = fields[10].GetUInt32(); + int32 castItemLevel = fields[11].GetInt32(); + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(key.SpellId, difficulty); if (!spellInfo) { TC_LOG_ERROR("entities.player", "Player::_LoadAuras: Player '%s' (%s) has an invalid aura (SpellID: %u), ignoring.", @@ -18850,6 +18851,13 @@ void Player::_LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effe continue; } + if (difficulty != DIFFICULTY_NONE && !sDifficultyStore.LookupEntry(difficulty)) + { + TC_LOG_ERROR("entities.player", "Player::_LoadAuras: Player '%s' (%s) has an invalid aura difficulty %u (SpellID: %u), ignoring.", + GetName().c_str(), GetGUID().ToString().c_str(), uint32(difficulty), key.SpellId); + continue; + } + // negative effects should continue counting down after logout if (remainTime != -1 && !spellInfo->IsPositive()) { @@ -18872,7 +18880,7 @@ void Player::_LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effe AuraLoadEffectInfo& info = effectInfo[key]; ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellInfo->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()); - if (Aura* aura = Aura::TryCreate(spellInfo, castId, key.EffectMask, this, nullptr, info.BaseAmounts.data(), nullptr, casterGuid, itemGuid, castItemId, castItemLevel)) + if (Aura* aura = Aura::TryCreate(spellInfo, castId, key.EffectMask, this, nullptr, difficulty, info.BaseAmounts.data(), nullptr, casterGuid, itemGuid, castItemId, castItemLevel)) { if (!aura->CanBeSaved()) { @@ -20813,6 +20821,7 @@ void Player::_SaveAuras(CharacterDatabaseTransaction& trans) stmt->setUInt32(index++, key.SpellId); stmt->setUInt32(index++, key.EffectMask); stmt->setUInt32(index++, recalculateMask); + stmt->setUInt8(index++, aura->GetCastDifficulty()); stmt->setUInt8(index++, aura->GetStackAmount()); stmt->setInt32(index++, aura->GetMaxDuration()); stmt->setInt32(index++, aura->GetDuration()); @@ -21771,7 +21780,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) { //returning of reagents only for players, so best done here uint32 spellId = pet ? *pet->m_unitData->CreatedBySpell : m_oldpetspell; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (spellInfo) { @@ -22094,7 +22103,7 @@ void Player::VehicleSpellInitialize() for (uint32 i = 0; i < MAX_CREATURE_SPELLS; ++i) { uint32 spellId = vehicle->m_spells[i]; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) continue; @@ -22106,7 +22115,7 @@ void Player::VehicleSpellInitialize() } if (spellInfo->IsPassive()) - vehicle->CastSpell(vehicle, spellId, true); + vehicle->CastSpell(vehicle, spellInfo, true); petSpells.ActionButtons[i] = MAKE_UNIT_ACTION_BUTTON(spellId, i + 8); } @@ -22182,7 +22191,7 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod template <class T> void Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& basevalue, Spell* spell /*= nullptr*/) const { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) return; @@ -23329,7 +23338,7 @@ void Player::UpdatePotionCooldown(Spell* spell) if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(m_lastPotionId)) for (uint8 idx = 0; idx < proto->Effects.size(); ++idx) if (proto->Effects[idx]->TriggerType == ITEM_SPELLTRIGGER_ON_USE) - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Effects[idx]->SpellID)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Effects[idx]->SpellID, DIFFICULTY_NONE)) GetSpellHistory()->SendCooldownEvent(spellInfo, m_lastPotionId); } // from spell cases (m_lastPotionId set in Spell::SendSpellCooldown) @@ -24282,10 +24291,11 @@ void Player::ApplyEquipCooldown(Item* pItem) std::chrono::steady_clock::time_point now = GameTime::GetGameTimeSteadyPoint(); for (ItemEffectEntry const* effectData : pItem->GetEffects()) { + SpellInfo const* effectSpellInfo = sSpellMgr->AssertSpellInfo(effectData->SpellID, DIFFICULTY_NONE); // apply proc cooldown to equip auras if we have any if (effectData->TriggerType == ITEM_SPELLTRIGGER_ON_EQUIP) { - SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(effectData->SpellID); + SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(effectSpellInfo); if (!procEntry) continue; @@ -24299,7 +24309,7 @@ void Player::ApplyEquipCooldown(Item* pItem) continue; // Don't replace longer cooldowns by equip cooldown if we have any. - if (GetSpellHistory()->GetRemainingCooldown(sSpellMgr->AssertSpellInfo(effectData->SpellID)) > 30 * IN_MILLISECONDS) + if (GetSpellHistory()->GetRemainingCooldown(effectSpellInfo) > 30 * IN_MILLISECONDS) continue; GetSpellHistory()->AddCooldown(effectData->SpellID, pItem->GetEntry(), std::chrono::seconds(30)); @@ -24333,7 +24343,7 @@ void Player::ResetSpells(bool myClassOnly) for (PlayerSpellMap::const_iterator iter = smap.begin(); iter != smap.end(); ++iter) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(iter->first); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(iter->first, DIFFICULTY_NONE); if (!spellInfo) continue; @@ -24458,13 +24468,13 @@ void Player::LearnQuestRewardedSpells(Quest const* quest) return; } - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, DIFFICULTY_NONE); if (!spellInfo) return; // check learned spells state bool found = false; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (effect && effect->Effect == SPELL_EFFECT_LEARN_SPELL && !HasSpell(effect->TriggerSpell)) { @@ -24477,7 +24487,7 @@ void Player::LearnQuestRewardedSpells(Quest const* quest) if (!found) return; - SpellEffectInfo const* effect = spellInfo->GetEffect(DIFFICULTY_NONE, EFFECT_0); + SpellEffectInfo const* effect = spellInfo->GetEffect(EFFECT_0); if (!effect) return; @@ -24525,7 +24535,7 @@ void Player::LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue) for (SkillLineAbilityEntry const* ability : *skillLineAbilities) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ability->Spell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ability->Spell, DIFFICULTY_NONE); if (!spellInfo) continue; @@ -26669,7 +26679,7 @@ TalentLearnResult Player::LearnPvpTalent(uint32 talentID, uint8 slot, int32* spe bool Player::AddPvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup, uint8 slot) { ASSERT(talent); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: %u) does not exist.", talent->SpellID); @@ -26696,7 +26706,7 @@ bool Player::AddPvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup, void Player::RemovePvpTalent(PvpTalentEntry const* talent) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID, DIFFICULTY_NONE); if (!spellInfo) return; @@ -26906,7 +26916,7 @@ void Player::SendTalentsInfoData() continue; } - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE); if (!spellEntry) { TC_LOG_ERROR("entities.player", "Player::SendTalentsInfoData: Player '%s' (%s) has unknown talent spell: %u", @@ -26930,7 +26940,7 @@ void Player::SendTalentsInfoData() continue; } - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE); if (!spellEntry) { TC_LOG_ERROR("entities.player", "Player::SendTalentsInfoData: Player '%s' (%s) has unknown pvp talent spell: %u", @@ -27334,14 +27344,14 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec) if (talentInfo->SpellID == 0) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE); if (!spellInfo) continue; RemoveSpell(talentInfo->SpellID, true); // search for spells that the talent teaches and unlearn them - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL) RemoveSpell(effect->TriggerSpell, true); @@ -27355,14 +27365,14 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec) if (!talentInfo) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE); if (!spellInfo) continue; RemoveSpell(talentInfo->SpellID, true); // search for spells that the talent teaches and unlearn them - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) if (effect && effect->TriggerSpell > 0 && effect->Effect == SPELL_EFFECT_LEARN_SPELL) RemoveSpell(effect->TriggerSpell, true); @@ -28407,7 +28417,7 @@ SpellInfo const* Player::GetCastSpellInfo(SpellInfo const* spellInfo) const auto overrides = m_overrideSpells.find(spellInfo->Id); if (overrides != m_overrideSpells.end()) for (uint32 spellId : overrides->second) - if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(spellId)) + if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID())) return Unit::GetCastSpellInfo(newInfo); return Unit::GetCastSpellInfo(spellInfo); @@ -28436,7 +28446,7 @@ void Player::LearnSpecializationSpells() for (size_t j = 0; j < specSpells->size(); ++j) { SpecializationSpellsEntry const* specSpell = (*specSpells)[j]; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID, DIFFICULTY_NONE); if (!spellInfo || spellInfo->SpellLevel > getLevel()) continue; diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp index 34f321d9cd3..c422bc181ca 100644 --- a/src/server/game/Entities/Totem/Totem.cpp +++ b/src/server/game/Entities/Totem/Totem.cpp @@ -73,7 +73,7 @@ void Totem::InitStats(uint32 duration) Minion::InitStats(duration); // Get spell cast by totem - if (SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(GetSpell())) + if (SpellInfo const* totemSpell = sSpellMgr->GetSpellInfo(GetSpell(), GetMap()->GetDifficultyID())) if (totemSpell->CalcCastTime(getLevel())) // If spell has cast time -> its an active totem m_type = TOTEM_ACTIVE; @@ -120,7 +120,7 @@ void Totem::UnSummon(uint32 msTime) { owner->SendAutoRepeatCancel(this); - if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(m_unitData->CreatedBySpell)) + if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(m_unitData->CreatedBySpell, GetMap()->GetDifficultyID())) GetSpellHistory()->SendCooldownEvent(spell, 0, nullptr, false); if (Group* group = owner->GetGroup()) @@ -142,17 +142,17 @@ bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Uni /// @todo possibly all negative auras immune? if (GetEntry() == 5925) return false; - if (SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficultyID(), index)) + if (SpellEffectInfo const* effect = spellInfo->GetEffect(index)) { switch (effect->ApplyAuraName) { - case SPELL_AURA_PERIODIC_DAMAGE: - case SPELL_AURA_PERIODIC_LEECH: - case SPELL_AURA_MOD_FEAR: - case SPELL_AURA_TRANSFORM: - return true; - default: - break; + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_LEECH: + case SPELL_AURA_MOD_FEAR: + case SPELL_AURA_TRANSFORM: + return true; + default: + break; } } else diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 88fb805a71d..29596e4b705 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -539,7 +539,7 @@ void Player::UpdateMastery() { if (Aura* aura = GetAura(chrSpec->MasterySpellID[i])) { - for (SpellEffectInfo const* effect : aura->GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : aura->GetSpellInfo()->GetEffects()) { if (!effect) continue; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 43ae9f624d0..29f2d6433ce 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -172,7 +172,7 @@ DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo) DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask) : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage), m_originalDamage(spellNonMeleeDamage.originalDamage), - m_spellInfo(sSpellMgr->GetSpellInfo(spellNonMeleeDamage.SpellID)), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType), + m_spellInfo(spellNonMeleeDamage.Spell), 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(hitMask) { if (spellNonMeleeDamage.blocked) @@ -278,8 +278,8 @@ SpellSchoolMask ProcEventInfo::GetSchoolMask() const return SPELL_SCHOOL_MASK_NONE; } -SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, uint32 _SpellID, uint32 _SpellXSpellVisualID, uint32 _schoolMask, ObjectGuid _castId) - : target(_target), attacker(_attacker), castId(_castId), SpellID(_SpellID), SpellXSpellVisualID(_SpellXSpellVisualID), damage(0), originalDamage(0), +SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellInfo const* _spellInfo, uint32 _SpellXSpellVisualID, uint32 _schoolMask, ObjectGuid _castId) + : target(_target), attacker(_attacker), castId(_castId), Spell(_spellInfo), SpellXSpellVisualID(_SpellXSpellVisualID), damage(0), originalDamage(0), schoolMask(_schoolMask), absorb(0), resist(0), periodicLog(false), blocked(0), HitInfo(0), cleanDamage(0), fullBlock(false), preHitHealth(_target->GetHealth()) { } @@ -884,7 +884,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam if (victim->GetTypeId() != TYPEID_PLAYER) { // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this - if (damagetype != DOT && damage > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(GetMap()->GetDifficultyID(), SPELL_AURA_DAMAGE_SHIELD))) + if (damagetype != DOT && damage > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD))) victim->ToCreature()->SetLastDamagedTime(GameTime::GetGameTime() + MAX_AGGRO_RESET_TIME); victim->AddThreat(this, float(damage), damageSchoolMask, spellProto); @@ -988,7 +988,7 @@ void Unit::CastSpell(Unit* victim, uint32 spellId, bool triggered, Item* castIte void Unit::CastSpell(Unit* victim, uint32 spellId, TriggerCastFlags triggerFlags /*= TRIGGER_NONE*/, Item* castItem /*= nullptr*/, AuraEffect const* triggeredByAura /*= nullptr*/, ObjectGuid originalCaster /*= ObjectGuid::Empty*/) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s", spellId, GetGUID().ToString().c_str()); @@ -1038,7 +1038,7 @@ void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const& value, Unit* victim, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, ObjectGuid originalCaster) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s", spellId, GetGUID().ToString().c_str()); @@ -1052,7 +1052,7 @@ void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const& value, Unit* void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, ObjectGuid originalCaster) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s", spellId, GetGUID().ToString().c_str()); @@ -1066,7 +1066,7 @@ void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, void Unit::CastSpell(float x, float y, float z, uint32 spellId, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, ObjectGuid originalCaster) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s", spellId, GetGUID().ToString().c_str()); @@ -1080,7 +1080,7 @@ void Unit::CastSpell(float x, float y, float z, uint32 spellId, TriggerCastFlags void Unit::CastSpell(GameObject* go, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, ObjectGuid originalCaster) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("entities.unit", "CastSpell: unknown spell id %u by caster: %s", spellId, GetGUID().ToString().c_str()); @@ -1220,16 +1220,15 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage const* damageInfo, bool durabilit if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())) return; - SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(damageInfo->SpellID); - if (!spellProto) + if (!damageInfo->Spell) { - TC_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has wrong damageInfo->SpellID: %u", damageInfo->SpellID); + TC_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has no spell"); return; } // Call default DealDamage CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss); + DealDamage(victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), damageInfo->Spell, durabilityLoss); } /// @todo for melee need create structure as in @@ -1576,7 +1575,7 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s if (effIndex != -1) { // bleeding effects are not reduced by armor - if (SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficultyID(), effIndex)) + if (SpellEffectInfo const* effect = spellInfo->GetEffect(effIndex)) { if (effect->ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE || effect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE) @@ -1938,7 +1937,7 @@ void Unit::CalcAbsorbResist(DamageInfo& damageInfo) uint32 split_absorb = 0; DealDamageMods(caster, splitDamage, &split_absorb); - SpellNonMeleeDamage log(this, caster, (*itr)->GetSpellInfo()->Id, (*itr)->GetBase()->GetSpellXSpellVisualId(), damageInfo.GetSchoolMask(), (*itr)->GetBase()->GetCastGUID()); + SpellNonMeleeDamage log(this, caster, (*itr)->GetSpellInfo(), (*itr)->GetBase()->GetSpellXSpellVisualId(), damageInfo.GetSchoolMask(), (*itr)->GetBase()->GetCastGUID()); CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL); DealDamage(caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false); log.damage = splitDamage; @@ -2360,12 +2359,12 @@ int32 Unit::GetMechanicResistChance(SpellInfo const* spellInfo) const return 0; int32 resistMech = 0; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (!effect || !effect->IsEffect()) break; - int32 effectMech = spellInfo->GetEffectMechanic(effect->EffectIndex, GetMap()->GetDifficultyID()); + int32 effectMech = spellInfo->GetEffectMechanic(effect->EffectIndex); if (effectMech) { int32 temp = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effectMech); @@ -3252,7 +3251,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint3 return nullptr; // update basepoints with new values - effect amount will be recalculated in ModStackAmount - for (SpellEffectInfo const* effect : foundAura->GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : newAura->GetEffects()) { if (!effect) continue; @@ -3522,12 +3521,12 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) SpellInfo const* spellProto = aura->GetSpellInfo(); // passive spell special case (only non stackable with ranks) - if (spellProto->IsPassiveStackableWithRanks(GetMap()->GetDifficultyID())) + if (spellProto->IsPassiveStackableWithRanks()) return; if (!IsHighestExclusiveAura(aura)) { - if (!aura->GetSpellInfo()->IsAffectingArea(GetMap()->GetDifficultyID())) + if (!aura->GetSpellInfo()->IsAffectingArea()) { Unit* caster = aura->GetCaster(); if (caster && caster->GetTypeId() == TYPEID_PLAYER) @@ -3896,7 +3895,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U if (aura->IsSingleTarget()) aura->UnregisterSingleTarget(); - if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), aura->GetCastGUID(), effMask, stealer, nullptr, &baseDamage[0], nullptr, aura->GetCasterGUID())) + if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), aura->GetCastGUID(), effMask, stealer, nullptr, aura->GetCastDifficulty(), &baseDamage[0], nullptr, aura->GetCasterGUID())) { // created aura must not be single target aura,, so stealer won't loose it on recast if (newAura->IsSingleTarget()) @@ -4086,7 +4085,7 @@ void Unit::RemoveMovementImpairingAuras(bool withRoot) } // turn off snare auras by setting amount to 0 - for (SpellEffectInfo const* effect : aura->GetSpellInfo()->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : aura->GetSpellInfo()->GetEffects()) { if (!effect || !effect->IsEffect()) continue; @@ -4252,7 +4251,7 @@ void Unit::RemoveAllAurasExceptType(AuraType type) for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();) { Aura const* aura = iter->second->GetBase(); - if (aura->GetSpellInfo()->HasAura(GetMap()->GetDifficultyID(), type)) + if (aura->GetSpellInfo()->HasAura(type)) ++iter; else _UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT); @@ -4261,7 +4260,7 @@ void Unit::RemoveAllAurasExceptType(AuraType type) for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();) { Aura* aura = iter->second; - if (aura->GetSpellInfo()->HasAura(GetMap()->GetDifficultyID(), type)) + if (aura->GetSpellInfo()->HasAura(type)) ++iter; else RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT); @@ -4273,7 +4272,7 @@ void Unit::RemoveAllAurasExceptType(AuraType type1, AuraType type2) for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();) { Aura const* aura = iter->second->GetBase(); - if (aura->GetSpellInfo()->HasAura(GetMap()->GetDifficultyID(), type1) || aura->GetSpellInfo()->HasAura(GetMap()->GetDifficultyID(), type2)) + if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2)) ++iter; else _UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT); @@ -4282,7 +4281,7 @@ void Unit::RemoveAllAurasExceptType(AuraType type1, AuraType type2) for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();) { Aura* aura = iter->second; - if (aura->GetSpellInfo()->HasAura(GetMap()->GetDifficultyID(), type1) || aura->GetSpellInfo()->HasAura(GetMap()->GetDifficultyID(), type2)) + if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2)) ++iter; else RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT); @@ -4572,9 +4571,9 @@ bool Unit::HasAuraWithMechanic(uint32 mechanicMask) const if (spellInfo->Mechanic && (mechanicMask & (1 << spellInfo->Mechanic))) return true; - for (SpellEffectInfo const* effect : iter->second->GetBase()->GetSpellEffectInfos()) - if (effect && effect->Effect && effect->Mechanic) - if (mechanicMask & (1 << effect->Mechanic)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) + if (effect && effect->Effect && effect->Mechanic) + if (mechanicMask & (1 << effect->Mechanic)) return true; } @@ -5035,7 +5034,7 @@ void Unit::AddGameObject(GameObject* gameObj) if (gameObj->GetSpellId()) { - SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId()); + SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId(), GetMap()->GetDifficultyID()); // Need disable spell use for owner if (createBySpell && createBySpell->IsCooldownStartedOnEvent()) // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) @@ -5067,7 +5066,7 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del) { RemoveAurasDueToSpell(spellid); - SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid); + SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid, GetMap()->GetDifficultyID()); // Need activate spell use for owner if (createBySpell && createBySpell->IsCooldownStartedOnEvent()) // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) @@ -5196,7 +5195,7 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const* log) packet.Me = log->target->GetGUID(); packet.CasterGUID = log->attacker->GetGUID(); packet.CastID = log->castId; - packet.SpellID = log->SpellID; + packet.SpellID = log->Spell ? log->Spell->Id : 0; packet.Damage = log->damage; packet.OriginalDamage = log->originalDamage; if (log->damage > log->preHitHealth) @@ -5862,7 +5861,7 @@ void Unit::ModifyAuraState(AuraStateType flag, bool apply) { if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE); if (!spellInfo || !spellInfo->IsPassive()) continue; if (spellInfo->CasterAuraState == uint32(flag)) @@ -5875,7 +5874,7 @@ void Unit::ModifyAuraState(AuraStateType flag, bool apply) { if (itr->second.state == PETSPELL_REMOVED) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE); if (!spellInfo || !spellInfo->IsPassive()) continue; if (spellInfo->CasterAuraState == uint32(flag)) @@ -6125,7 +6124,7 @@ void Unit::SetMinion(Minion *minion, bool apply) minion->SetSpeedRate(UnitMoveType(i), m_speed_rate[i]); // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, GetMap()->GetDifficultyID()); if (spellInfo && (spellInfo->IsCooldownStartedOnEvent())) GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true); @@ -6152,8 +6151,8 @@ void Unit::SetMinion(Minion *minion, bool apply) else if (minion->IsTotem()) { // All summoned by totem minions must disappear when it is removed. - if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell())) - for (SpellEffectInfo const* effect : spInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell(), GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spInfo->GetEffects()) { if (!effect || effect->Effect != SPELL_EFFECT_SUMMON) continue; @@ -6162,7 +6161,7 @@ void Unit::SetMinion(Minion *minion, bool apply) } } - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, GetMap()->GetDifficultyID()); // Remove infinity cooldown if (spellInfo && (spellInfo->IsCooldownStartedOnEvent())) GetSpellHistory()->SendCooldownEvent(spellInfo); @@ -6619,7 +6618,7 @@ void Unit::EnergizeBySpell(Unit* victim, uint32 spellId, int32 damage, Powers po int32 gain = victim->ModifyPower(powerType, damage); int32 overEnergize = damage - gain; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); victim->getHostileRefManager().threatAssist(this, float(damage) * 0.5f, spellInfo); SendEnergizeSpellLog(victim, spellId, damage, overEnergize, powerType); @@ -7142,7 +7141,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack); } - for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellProto->GetEffects()) { if (!effect) continue; @@ -7257,7 +7256,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u return false; }); - for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellProto->GetEffects()) { if (!effect) continue; @@ -7363,7 +7362,7 @@ bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const uint32 schoolImmunityMask = 0; SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr) - if ((itr->first & schoolMask) && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second))) + if ((itr->first & schoolMask) && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second, GetMap()->GetDifficultyID()))) schoolImmunityMask |= itr->first; // // We need to be immune to all types @@ -7408,7 +7407,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const } bool immuneToAllEffects = true; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { // State/effect immunities applied by aura expect full spell immunity // Ignore effects with mechanic, they are supposed to be checked separately @@ -7433,7 +7432,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const if ((itr->first & schoolMask) == 0) continue; - SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second); + SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second, GetMap()->GetDifficultyID()); if (!(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive() && caster && IsFriendlyTo(caster))) if (!spellInfo->CanPierceImmuneAura(immuneSpellInfo)) schoolImmunityMask |= itr->first; @@ -7480,7 +7479,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit if (!spellInfo) return false; - SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficultyID(), index); + SpellEffectInfo const* effect = spellInfo->GetEffect(index); if (!effect) return false; @@ -7559,7 +7558,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType if (APbonus != 0) // Can be negative { - bool const normalized = spellProto && spellProto->HasEffect(GetMap()->GetDifficultyID(), SPELL_EFFECT_NORMALIZED_WEAPON_DMG); + bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG); DoneFlatBenefit += int32(APbonus / 3.5f * GetAPMultiplier(attType, normalized)); } @@ -8126,12 +8125,12 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo // can't attack invisible if (!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) { - if (obj && !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea(GetMap()->GetDifficultyID()))) + if (obj && !obj->CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())) return false; else if (!obj) { // ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player - bool const ignoreStealthCheck = (bySpell && bySpell->IsAffectingArea(GetMap()->GetDifficultyID())) || + bool const ignoreStealthCheck = (bySpell && bySpell->IsAffectingArea()) || (target->GetTypeId() == TYPEID_PLAYER && target->HasStealthAura() && target->IsInCombat() && IsInCombatWith(target)); if (!CanSeeOrDetect(target, ignoreStealthCheck)) @@ -8252,7 +8251,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co return false; // can't assist invisible - if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea(GetMap()->GetDifficultyID()))) + if ((!bySpell || !bySpell->HasAttribute(SPELL_ATTR6_CAN_TARGET_INVISIBLE)) && !CanSeeOrDetect(target, bySpell && bySpell->IsAffectingArea())) return false; // can't assist dead @@ -9045,7 +9044,7 @@ float Unit::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index // function uses real base points (typically value - 1) int32 Unit::CalculateSpellDamage(Unit const* target, SpellInfo const* spellProto, uint8 effect_index, int32 const* basePoints /*= nullptr*/, float* variance /*= nullptr*/, uint32 castItemId /*= 0*/, int32 itemLevel /*= -1*/) const { - SpellEffectInfo const* effect = spellProto->GetEffect(GetMap()->GetDifficultyID(), effect_index); + SpellEffectInfo const* effect = spellProto->GetEffect(effect_index); if (variance) *variance = 0.0f; @@ -9137,7 +9136,7 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in sSpellMgr->IsSpellMemberOfSpellGroup(spellProto->Id, SPELL_GROUP_ELIXIR_BATTLE) || sSpellMgr->IsSpellMemberOfSpellGroup(spellProto->Id, SPELL_GROUP_ELIXIR_GUARDIAN))) { - SpellEffectInfo const* effect = spellProto->GetEffect(DIFFICULTY_NONE, EFFECT_0); + SpellEffectInfo const* effect = spellProto->GetEffect(EFFECT_0); if (target->HasAura(53042) && effect && target->HasSpell(effect->TriggerSpell)) duration *= 2; } @@ -9378,7 +9377,7 @@ bool Unit::IsInDisallowedMountForm() const bool Unit::IsDisallowedMountForm(uint32 spellId, ShapeshiftForm form, uint32 displayId) const { - if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(spellId)) + if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID())) if (transformSpellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED)) return false; @@ -10152,7 +10151,7 @@ void CharmInfo::InitPossessCreateSpells() for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i) { uint32 spellId = _unit->ToCreature()->m_spells[i]; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, _unit->GetMap()->GetDifficultyID()); if (spellInfo) { if (spellInfo->IsPassive()) @@ -10179,7 +10178,7 @@ void CharmInfo::InitCharmCreateSpells() for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x) { uint32 spellId = _unit->ToCreature()->m_spells[x]; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, _unit->GetMap()->GetDifficultyID()); if (!spellInfo) { @@ -10309,7 +10308,7 @@ void CharmInfo::LoadPetActionBar(const std::string& data) // check correctness if (PetActionBar[index].IsActionBarForSpell()) { - SpellInfo const* spelInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction()); + SpellInfo const* spelInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction(), _unit->GetMap()->GetDifficultyID()); if (!spelInfo) SetActionBar(index, 0, ACT_PASSIVE); else if (!spelInfo->IsAutocastable()) @@ -10731,7 +10730,7 @@ bool Unit::IsPolymorphed() const if (!transformId) return false; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(transformId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(transformId, GetMap()->GetDifficultyID()); if (!spellInfo) return false; @@ -10974,7 +10973,7 @@ uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectTyp bool DirectDamage = false; bool AreaEffect = false; - for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellProto->GetEffects()) { if (!effect) continue; @@ -11033,7 +11032,7 @@ uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectTyp CastingTime /= 2; // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellProto->GetEffects()) { if (!effect) continue; @@ -11089,7 +11088,7 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect if (!spellInfo->IsChanneled() && DotDuration > 0) DotFactor = DotDuration / 15000.0f; - if (uint32 DotTicks = spellInfo->GetMaxTicks(GetMap()->GetDifficultyID())) + if (uint32 DotTicks = spellInfo->GetMaxTicks()) DotFactor /= DotTicks; } @@ -12251,7 +12250,7 @@ Aura* Unit::AddAura(uint32 spellId, Unit* target) if (!target) return NULL; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()); if (!spellInfo) return NULL; @@ -12278,7 +12277,7 @@ Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target) } ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellInfo->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()); - if (Aura* aura = Aura::TryRefreshStackOrCreate(spellInfo, castId, effMask, target, this)) + if (Aura* aura = Aura::TryRefreshStackOrCreate(spellInfo, castId, effMask, target, this, GetMap()->GetDifficultyID())) { aura->ApplyForTargets(); return aura; @@ -13023,14 +13022,14 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) Unit* target = (itr->second.castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this; ObjectGuid origCasterGUID = (itr->second.castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID(); - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(itr->second.spellId); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(itr->second.spellId, caster->GetMap()->GetDifficultyID()); // if (!spellEntry) should be checked at npc_spellclick load if (seatId > -1) { uint8 i = 0; bool valid = false; - for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellEntry->GetEffects()) { if (!effect) continue; @@ -13054,12 +13053,12 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) else // This can happen during Player::_LoadAuras { int32 bp0[MAX_SPELL_EFFECTS]; - for (SpellEffectInfo const* effect : spellEntry->GetEffectsForDifficulty(GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellEntry->GetEffects()) if (effect) bp0[effect->EffectIndex] = effect->BasePoints; bp0[i] = seatId; - Aura::TryRefreshStackOrCreate(spellEntry, ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), MAX_EFFECT_MASK, this, clicker, bp0, NULL, origCasterGUID); + Aura::TryRefreshStackOrCreate(spellEntry, ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), MAX_EFFECT_MASK, this, clicker, GetMap()->GetDifficultyID(), bp0, NULL, origCasterGUID); } } else @@ -13067,7 +13066,7 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) if (IsInMap(caster)) caster->CastSpell(target, spellEntry, flags, NULL, NULL, origCasterGUID); else - Aura::TryRefreshStackOrCreate(spellEntry, ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), MAX_EFFECT_MASK, this, clicker, NULL, NULL, origCasterGUID); + Aura::TryRefreshStackOrCreate(spellEntry, ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), MAX_EFFECT_MASK, this, clicker, GetMap()->GetDifficultyID(), NULL, NULL, origCasterGUID); } result = true; @@ -14495,7 +14494,7 @@ SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const { bool matches = auraEffect->GetMiscValue() ? uint32(auraEffect->GetMiscValue()) == spellInfo->Id : auraEffect->IsAffectingSpell(spellInfo); if (matches) - if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount())) + if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount(), GetMap()->GetDifficultyID())) return newInfo; } @@ -14518,7 +14517,7 @@ uint32 Unit::GetCastSpellXSpellVisualId(SpellInfo const* spellInfo) const { if (uint32(effect->GetMiscValue()) == spellInfo->Id) { - if (SpellInfo const* visualSpell = sSpellMgr->GetSpellInfo(effect->GetMiscValueB())) + if (SpellInfo const* visualSpell = sSpellMgr->GetSpellInfo(effect->GetMiscValueB(), GetMap()->GetDifficultyID())) { spellInfo = visualSpell; break; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 48ab77e3856..f6ac8d6d3f5 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -685,12 +685,12 @@ struct CalcDamageInfo // Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode struct TC_GAME_API SpellNonMeleeDamage { - SpellNonMeleeDamage(Unit* _attacker, Unit* _target, uint32 _SpellID, uint32 _SpellXSpellVisualID, uint32 _schoolMask, ObjectGuid _castId = ObjectGuid::Empty); + SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellInfo const* _spellInfo, uint32 _SpellXSpellVisualID, uint32 _schoolMask, ObjectGuid _castId = ObjectGuid::Empty); Unit *target; Unit *attacker; ObjectGuid castId; - uint32 SpellID; + SpellInfo const* Spell; uint32 SpellXSpellVisualID; uint32 damage; uint32 originalDamage; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 0b2b6ca4ae6..e38539429ae 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -639,14 +639,14 @@ void ObjectMgr::LoadCreatureTemplateAddons() for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) { uint32 spellId = uint32(atoul(*itr)); - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!AdditionalSpellInfo) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %u defined in `auras` field in `creature_template_addon`.", entry, spellId); continue; } - if (AdditionalSpellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_CONTROL_VEHICLE)) + if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_template_addon`.", entry, spellId); if (std::find(creatureAddon.auras.begin(), creatureAddon.auras.end(), spellId) != creatureAddon.auras.end()) @@ -1024,7 +1024,7 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) for (uint8 j = 0; j < MAX_CREATURE_SPELLS; ++j) { - if (cInfo->spells[j] && !sSpellMgr->GetSpellInfo(cInfo->spells[j])) + if (cInfo->spells[j] && !sSpellMgr->GetSpellInfo(cInfo->spells[j], DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing Spell%d (%u), set to 0.", cInfo->Entry, j+1, cInfo->spells[j]); const_cast<CreatureTemplate*>(cInfo)->spells[j] = 0; @@ -1124,14 +1124,14 @@ void ObjectMgr::LoadCreatureAddons() for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) { uint32 spellId = uint32(atoul(*itr)); - SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!AdditionalSpellInfo) { TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has wrong spell %u defined in `auras` field in `creature_addon`.", guid, spellId); continue; } - if (AdditionalSpellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_CONTROL_VEHICLE)) + if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_addon`.", guid, spellId); if (std::find(creatureAddon.auras.begin(), creatureAddon.auras.end(), spellId) != creatureAddon.auras.end()) @@ -4273,7 +4273,7 @@ void ObjectMgr::LoadQuests() if (qinfo->_sourceSpellID) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->_sourceSpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->_sourceSpellID, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("sql.sql", "Quest %u has `SourceSpellid` = %u but spell %u doesn't exist, quest can't be done.", @@ -4356,7 +4356,7 @@ void ObjectMgr::LoadQuests() TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid currency amount %d", qinfo->GetQuestId(), obj.ID, obj.Amount); break; case QUEST_OBJECTIVE_LEARNSPELL: - if (!sSpellMgr->GetSpellInfo(obj.ObjectID)) + if (!sSpellMgr->GetSpellInfo(obj.ObjectID, DIFFICULTY_NONE)) TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing spell id %d", qinfo->GetQuestId(), obj.ID, obj.ObjectID); break; case QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC: @@ -4489,7 +4489,7 @@ void ObjectMgr::LoadQuests() { if (qinfo->RewardDisplaySpell[i]) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardDisplaySpell[i]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardDisplaySpell[i], DIFFICULTY_NONE); if (!spellInfo) { @@ -4509,7 +4509,7 @@ void ObjectMgr::LoadQuests() if (qinfo->_rewardSpell > 0) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->_rewardSpell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->_rewardSpell, DIFFICULTY_NONE); if (!spellInfo) { @@ -4679,13 +4679,13 @@ void ObjectMgr::LoadQuests() } // check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE - for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i) + for (SpellNameEntry const* spellNameEntry : sSpellNameStore) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(i); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellNameEntry->ID, DIFFICULTY_NONE); if (!spellInfo) continue; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) { if (!effect || effect->Effect != SPELL_EFFECT_QUEST_COMPLETE) continue; @@ -5136,7 +5136,7 @@ void ObjectMgr::LoadScripts(ScriptsType type) case SCRIPT_COMMAND_REMOVE_AURA: { - if (!sSpellMgr->GetSpellInfo(tmp.RemoveAura.SpellID)) + if (!sSpellMgr->GetSpellInfo(tmp.RemoveAura.SpellID, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA for script id %u", tableName.c_str(), tmp.RemoveAura.SpellID, tmp.id); @@ -5153,7 +5153,7 @@ void ObjectMgr::LoadScripts(ScriptsType type) case SCRIPT_COMMAND_CAST_SPELL: { - if (!sSpellMgr->GetSpellInfo(tmp.CastSpell.SpellID)) + if (!sSpellMgr->GetSpellInfo(tmp.CastSpell.SpellID, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_CAST_SPELL for script id %u", tableName.c_str(), tmp.CastSpell.SpellID, tmp.id); @@ -5239,7 +5239,7 @@ void ObjectMgr::LoadSpellScripts() for (ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr) { uint32 spellId = uint32(itr->first) & 0x00FFFFFF; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!spellInfo) { @@ -5267,9 +5267,9 @@ void ObjectMgr::LoadEventScripts() evt_scripts.insert(eventId); // Load all possible script entries from spells - for (uint32 i = 1; i < sSpellMgr->GetSpellInfoStoreSize(); ++i) - if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(i)) - for (SpellEffectInfo const* effect : spell->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellNameEntry const* spellNameEntry : sSpellNameStore) + if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellNameEntry->ID, DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spell->GetEffects()) if (effect && effect->Effect == SPELL_EFFECT_SEND_EVENT) if (effect->MiscValue) evt_scripts.insert(effect->MiscValue); @@ -5358,7 +5358,7 @@ void ObjectMgr::LoadSpellScriptNames() spellId = -spellId; } - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) does not exist.", scriptName.c_str(), fields[0].GetInt32()); @@ -5410,7 +5410,7 @@ void ObjectMgr::ValidateSpellScripts() for (auto spell : _spellScriptsStore) { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spell.first); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spell.first, DIFFICULTY_NONE); auto const bounds = sObjectMgr->GetSpellScriptsBounds(spell.first); @@ -5662,7 +5662,7 @@ void ObjectMgr::LoadInstanceEncounters() break; } case ENCOUNTER_CREDIT_CAST_SPELL: - if (!sSpellMgr->GetSpellInfo(creditEntry)) + if (!sSpellMgr->GetSpellInfo(creditEntry, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid spell (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->Name->Str[sWorld->GetDefaultDbcLocale()]); @@ -6963,7 +6963,7 @@ inline void CheckGOLinkedTrapId(GameObjectTemplate const* goInfo, uint32 dataN, inline void CheckGOSpellId(GameObjectTemplate const* goInfo, uint32 dataN, uint32 N) { - if (sSpellMgr->GetSpellInfo(dataN)) + if (sSpellMgr->GetSpellInfo(dataN, DIFFICULTY_NONE)) return; TC_LOG_ERROR("sql.sql", "Gameobject (Entry: %u GoType: %u) have data%d=%u but Spell (Entry %u) not exist.", @@ -7798,7 +7798,7 @@ void ObjectMgr::LoadNPCSpellClickSpells() } uint32 spellid = fields[1].GetUInt32(); - SpellInfo const* spellinfo = sSpellMgr->GetSpellInfo(spellid); + SpellInfo const* spellinfo = sSpellMgr->GetSpellInfo(spellid, DIFFICULTY_NONE); if (!spellinfo) { TC_LOG_ERROR("sql.sql", "Table npc_spellclick_spells creature: %u references unknown spellid %u. Skipping entry.", npc_entry, spellid); @@ -8637,7 +8637,7 @@ void ObjectMgr::LoadTrainers() spell.ReqAbility[2] = fields[7].GetUInt32(); spell.ReqLevel = fields[8].GetUInt8(); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell.SpellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell.SpellId, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing spell (SpellId: %u) for TrainerId %u, ignoring", spell.SpellId, trainerId); @@ -8655,7 +8655,7 @@ void ObjectMgr::LoadTrainers() for (std::size_t i = 0; i < spell.ReqAbility.size(); ++i) { uint32 requiredSpell = spell.ReqAbility[i]; - if (requiredSpell && !sSpellMgr->GetSpellInfo(requiredSpell)) + if (requiredSpell && !sSpellMgr->GetSpellInfo(requiredSpell, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing spell (ReqAbility" SZFMTD ": %u) for TrainerId %u and SpellId %u, ignoring", i + 1, requiredSpell, spell.SpellId, trainerId); @@ -9471,9 +9471,9 @@ void ObjectMgr::LoadFactionChangeSpells() uint32 alliance = fields[0].GetUInt32(); uint32 horde = fields[1].GetUInt32(); - if (!sSpellMgr->GetSpellInfo(alliance)) + if (!sSpellMgr->GetSpellInfo(alliance, DIFFICULTY_NONE)) TC_LOG_ERROR("sql.sql", "Spell %u (alliance_id) referenced in `player_factionchange_spells` does not exist, pair skipped!", alliance); - else if (!sSpellMgr->GetSpellInfo(horde)) + else if (!sSpellMgr->GetSpellInfo(horde, DIFFICULTY_NONE)) TC_LOG_ERROR("sql.sql", "Spell %u (horde_id) referenced in `player_factionchange_spells` does not exist, pair skipped!", horde); else FactionChangeSpells[alliance] = horde; diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 7428cb9994e..3d91ce9afaa 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -21,6 +21,7 @@ #include "DatabaseEnv.h" #include "Group.h" #include "Log.h" +#include "Map.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" @@ -86,7 +87,7 @@ void WorldSession::HandlePetAction(WorldPackets::Pet::PetAction& packet) if (!pet->IsAlive()) { - SpellInfo const* spell = (flag == ACT_ENABLED || flag == ACT_PASSIVE) ? sSpellMgr->GetSpellInfo(spellid) : NULL; + SpellInfo const* spell = (flag == ACT_ENABLED || flag == ACT_PASSIVE) ? sSpellMgr->GetSpellInfo(spellid, pet->GetMap()->GetDifficultyID()) : NULL; if (!spell) return; if (!spell->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD)) @@ -295,14 +296,14 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe unit_target = ObjectAccessor::GetUnit(*_player, guid2); // do not cast unknown spells - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid, pet->GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("spells.pet", "WORLD: unknown PET spell id %i", spellid); return; } - for (SpellEffectInfo const* effect: spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect: spellInfo->GetEffects()) { if (effect && (effect->TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || effect->TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || effect->TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY)) return; @@ -484,7 +485,7 @@ void WorldSession::HandlePetSetAction(WorldPackets::Pet::PetSetAction& packet) //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, pet->GetMap()->GetDifficultyID())) { //sign for autocast if (act_state == ACT_ENABLED) @@ -615,7 +616,7 @@ void WorldSession::HandlePetSpellAutocastOpcode(WorldPackets::Pet::PetSpellAutoc return; } - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.SpellID, pet->GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("spells.pet", "WorldSession::HandlePetSpellAutocastOpcode: Unknown spell id %u used by %s.", packet.SpellID, packet.PetGUID.ToString().c_str()); @@ -643,18 +644,18 @@ void WorldSession::HandlePetSpellAutocastOpcode(WorldPackets::Pet::PetSpellAutoc void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& petCastSpell) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petCastSpell.Cast.SpellID); - if (!spellInfo) + Unit* caster = ObjectAccessor::GetUnit(*_player, petCastSpell.PetGUID); + if (!caster) { - TC_LOG_ERROR("spells.pet", "WorldSession::HandlePetCastSpellOpcode: unknown spell id %i tried to cast by %s", - petCastSpell.Cast.SpellID, petCastSpell.PetGUID.ToString().c_str()); + TC_LOG_ERROR("entities.pet", "WorldSession::HandlePetCastSpellOpcode: Caster %s not found.", petCastSpell.PetGUID.ToString().c_str()); return; } - Unit* caster = ObjectAccessor::GetUnit(*_player, petCastSpell.PetGUID); - if (!caster) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petCastSpell.Cast.SpellID, caster->GetMap()->GetDifficultyID()); + if (!spellInfo) { - TC_LOG_ERROR("entities.pet", "WorldSession::HandlePetCastSpellOpcode: Caster %s not found.", petCastSpell.PetGUID.ToString().c_str()); + TC_LOG_ERROR("spells.pet", "WorldSession::HandlePetCastSpellOpcode: unknown spell id %i tried to cast by %s", + petCastSpell.Cast.SpellID, petCastSpell.PetGUID.ToString().c_str()); return; } @@ -706,7 +707,7 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPackets::Spells::PetCastSpell& { spell->SendPetCastResult(result); - if (!caster->GetSpellHistory()->HasCooldown(spellInfo->Id)) + if (!caster->GetSpellHistory()->HasCooldown(spellInfo)) caster->GetSpellHistory()->ResetCooldown(spellInfo->Id, true); spell->finish(false); diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 7c079d3a40a..db35fca9e07 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -25,6 +25,7 @@ #include "GuildMgr.h" #include "Item.h" #include "Log.h" +#include "Map.h" #include "Player.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" @@ -97,7 +98,7 @@ void WorldSession::HandleUseItemOpcode(WorldPackets::Spells::UseItem& packet) { for (ItemEffectEntry const* effect : item->GetEffects()) { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effect->SpellID)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effect->SpellID, user->GetMap()->GetDifficultyID())) { if (!spellInfo->CanBeUsedInCombat()) { @@ -275,7 +276,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast) if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) return; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cast.Cast.SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cast.Cast.SpellID, mover->GetMap()->GetDifficultyID()); if (!spellInfo) { TC_LOG_ERROR("network", "WORLD: unknown spell id %u", cast.Cast.SpellID); @@ -350,7 +351,7 @@ void WorldSession::HandleCancelCastOpcode(WorldPackets::Spells::CancelCast& pack void WorldSession::HandleCancelAuraOpcode(WorldPackets::Spells::CancelAura& cancelAura) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cancelAura.SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cancelAura.SpellID, _player->GetMap()->GetDifficultyID()); if (!spellInfo) return; @@ -376,7 +377,7 @@ void WorldSession::HandleCancelAuraOpcode(WorldPackets::Spells::CancelAura& canc _player->RemoveOwnedAura(cancelAura.SpellID, cancelAura.CasterGUID, 0, AURA_REMOVE_BY_CANCEL); // If spell being removed is a resource tracker, see if player was tracking both (herbs / minerals) and remove the other - if (sWorld->getBoolConfig(CONFIG_ALLOW_TRACK_BOTH_RESOURCES) && spellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_TRACK_RESOURCES)) + if (sWorld->getBoolConfig(CONFIG_ALLOW_TRACK_BOTH_RESOURCES) && spellInfo->HasAura(SPELL_AURA_TRACK_RESOURCES)) { Unit::AuraEffectList const& auraEffects = _player->GetAuraEffectsByType(SPELL_AURA_TRACK_RESOURCES); if (!auraEffects.empty()) @@ -397,8 +398,7 @@ void WorldSession::HandleCancelAuraOpcode(WorldPackets::Spells::CancelAura& canc void WorldSession::HandlePetCancelAuraOpcode(WorldPackets::Spells::PetCancelAura& packet) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.SpellID); - if (!spellInfo) + if (sSpellMgr->GetSpellInfo(packet.SpellID, DIFFICULTY_NONE)) { TC_LOG_ERROR("network", "WORLD: unknown PET spell id %u", packet.SpellID); return; @@ -491,7 +491,7 @@ void WorldSession::HandleSelfResOpcode(WorldPackets::Spells::SelfRes& selfRes) if (std::find(selfResSpells.begin(), selfResSpells.end(), selfRes.SpellID) == selfResSpells.end()) return; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(selfRes.SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(selfRes.SpellID, _player->GetMap()->GetDifficultyID()); if (spellInfo) _player->CastSpell(_player, spellInfo, false, nullptr); diff --git a/src/server/game/Handlers/ToyHandler.cpp b/src/server/game/Handlers/ToyHandler.cpp index 44351ddbacf..42a0408b6e3 100644 --- a/src/server/game/Handlers/ToyHandler.cpp +++ b/src/server/game/Handlers/ToyHandler.cpp @@ -69,7 +69,7 @@ void WorldSession::HandleUseToy(WorldPackets::Toy::UseToy& packet) if (effect == item->Effects.end()) return; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.Cast.SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.Cast.SpellID, DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("network", "HandleUseToy: unknown spell id: %u used by Toy Item entry %u", packet.Cast.SpellID, itemId); diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 8563528df03..95da9a2f69e 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -22,6 +22,7 @@ #include "Item.h" #include "Language.h" #include "Log.h" +#include "Map.h" #include "ObjectAccessor.h" #include "Player.h" #include "SocialMgr.h" @@ -353,7 +354,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPackets::Trade::AcceptTrade& acc // not accept if spell can't be cast now (cheating) if (uint32 my_spell_id = my_trade->GetSpell()) { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id, _player->GetMap()->GetDifficultyID()); Item* castItem = my_trade->GetSpellCastItem(); if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || @@ -388,7 +389,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPackets::Trade::AcceptTrade& acc // not accept if spell can't be cast now (cheating) if (uint32 his_spell_id = his_trade->GetSpell()) { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id, trader->GetMap()->GetDifficultyID()); Item* castItem = his_trade->GetSpellCastItem(); if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index b7f20ee3fd0..0ed93f24730 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -1094,9 +1094,9 @@ void LoadLootTemplates_Spell() uint32 count = LootTemplates_Spell.LoadAndCollectLootIds(lootIdSet); // remove real entries and check existence loot - for (uint32 spell_id = 1; spell_id < sSpellMgr->GetSpellInfoStoreSize(); ++spell_id) + for (SpellNameEntry const* spellNameEntry : sSpellNameStore) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellNameEntry->ID, DIFFICULTY_NONE); if (!spellInfo) continue; @@ -1104,15 +1104,15 @@ void LoadLootTemplates_Spell() if (!spellInfo->IsLootCrafting()) continue; - if (lootIdSet.find(spell_id) == lootIdSet.end()) + if (lootIdSet.find(spellInfo->Id) == lootIdSet.end()) { // not report about not trainable spells (optionally supported by DB) // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example if (!spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT) || (spellInfo->HasAttribute(SPELL_ATTR0_TRADESPELL))) - LootTemplates_Spell.ReportNonExistingId(spell_id, "Spell", spellInfo->Id); + LootTemplates_Spell.ReportNonExistingId(spellInfo->Id, "Spell", spellInfo->Id); } else - lootIdSet.erase(spell_id); + lootIdSet.erase(spellInfo->Id); } // output error for any still listed (not referenced from appropriate table) ids diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index b70f38a8970..b912f51cf9d 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -1131,7 +1131,7 @@ ScriptMgr* ScriptMgr::instance() void ScriptMgr::Initialize() { - ASSERT(sSpellMgr->GetSpellInfo(SPELL_HOTSWAP_VISUAL_SPELL_EFFECT) + ASSERT(sSpellMgr->GetSpellInfo(SPELL_HOTSWAP_VISUAL_SPELL_EFFECT, DIFFICULTY_NONE) && "Reload hotswap spell effect for creatures isn't valid!"); uint32 oldMSTime = getMSTime(); @@ -1228,8 +1228,7 @@ void ScriptMgr::Unload() { sScriptRegistryCompositum->Unload(); - delete[] SpellSummary; - delete[] UnitAI::AISpellInfo; + UnitAI::AISpellInfo.clear(); } void ScriptMgr::LoadDatabase() @@ -1241,91 +1240,6 @@ void ScriptMgr::LoadDatabase() void ScriptMgr::FillSpellSummary() { UnitAI::FillAISpellInfo(); - - SpellSummary = new TSpellSummary[sSpellMgr->GetSpellInfoStoreSize()]; - - SpellInfo const* pTempSpell; - - for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i) - { - SpellSummary[i].Effects = 0; - SpellSummary[i].Targets = 0; - - pTempSpell = sSpellMgr->GetSpellInfo(i); - // This spell doesn't exist. - if (!pTempSpell) - continue; - - for (SpellEffectInfo const* effect : pTempSpell->GetEffectsForDifficulty(DIFFICULTY_NONE)) - { - if (!effect) - continue; - - // Spell targets self. - if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); - - // Spell targets a single enemy. - if (effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || - effect->TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1); - - // Spell targets AoE at enemy. - if (effect->TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || - effect->TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || - effect->TargetA.GetTarget() == TARGET_SRC_CASTER || - effect->TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); - - // Spell targets an enemy. - if (effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ENEMY || - effect->TargetA.GetTarget() == TARGET_DEST_TARGET_ENEMY || - effect->TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || - effect->TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || - effect->TargetA.GetTarget() == TARGET_SRC_CASTER || - effect->TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1); - - // Spell targets a single friend (or self). - if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER || - effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY || - effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1); - - // Spell targets AoE friends. - if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY || - effect->TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY || - effect->TargetA.GetTarget() == TARGET_SRC_CASTER) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); - - // Spell targets any friend (or self). - if (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER || - effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_ALLY || - effect->TargetA.GetTarget() == TARGET_UNIT_TARGET_PARTY || - effect->TargetA.GetTarget() == TARGET_UNIT_CASTER_AREA_PARTY || - effect->TargetA.GetTarget() == TARGET_UNIT_LASTTARGET_AREA_PARTY || - effect->TargetA.GetTarget() == TARGET_SRC_CASTER) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); - - // Make sure that this spell includes a damage effect. - if (effect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE || - effect->Effect == SPELL_EFFECT_INSTAKILL || - effect->Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || - effect->Effect == SPELL_EFFECT_HEALTH_LEECH) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE-1); - - // Make sure that this spell includes a healing effect (or an apply aura with a periodic heal). - if (effect->Effect == SPELL_EFFECT_HEAL || - effect->Effect == SPELL_EFFECT_HEAL_MAX_HEALTH || - effect->Effect == SPELL_EFFECT_HEAL_MECHANICAL || - (effect->Effect == SPELL_EFFECT_APPLY_AURA && effect->ApplyAuraName == 8)) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1); - - // Make sure that this spell applies an aura. - if (effect->Effect == SPELL_EFFECT_APPLY_AURA) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); - } - } } template<typename T, typename F, typename O> diff --git a/src/server/game/Skills/SkillDiscovery.cpp b/src/server/game/Skills/SkillDiscovery.cpp index 2529060e6b3..1117589d0ab 100644 --- a/src/server/game/Skills/SkillDiscovery.cpp +++ b/src/server/game/Skills/SkillDiscovery.cpp @@ -16,6 +16,7 @@ */ #include "DatabaseEnv.h" +#include "DB2Stores.h" #include "Log.h" #include "World.h" #include "Util.h" @@ -84,7 +85,7 @@ void LoadSkillDiscoveryTable() if (reqSkillOrSpell > 0) // spell case { uint32 absReqSkillOrSpell = uint32(reqSkillOrSpell); - SpellInfo const* reqSpellInfo = sSpellMgr->GetSpellInfo(absReqSkillOrSpell); + SpellInfo const* reqSpellInfo = sSpellMgr->GetSpellInfo(absReqSkillOrSpell, DIFFICULTY_NONE); if (!reqSpellInfo) { if (reportedReqSpells.find(absReqSkillOrSpell) == reportedReqSpells.end()) @@ -139,9 +140,9 @@ void LoadSkillDiscoveryTable() TC_LOG_ERROR("sql.sql", "Some items can't be successfully discovered, their chance field value is < 0.000001 in the `skill_discovery_template` DB table. List:\n%s", ssNonDiscoverableEntries.str().c_str()); // report about empty data for explicit discovery spells - for (uint32 spell_id = 1; spell_id < sSpellMgr->GetSpellInfoStoreSize(); ++spell_id) + for (SpellNameEntry const* spellNameEntry : sSpellNameStore) { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spellNameEntry->ID, DIFFICULTY_NONE); if (!spellEntry) continue; @@ -149,8 +150,8 @@ void LoadSkillDiscoveryTable() if (!spellEntry->IsExplicitDiscovery()) continue; - if (SkillDiscoveryStore.find(int32(spell_id)) == SkillDiscoveryStore.end()) - TC_LOG_ERROR("sql.sql", "Spell (ID: %u) has got 100%% chance random discovery ability, but does not have data in the `skill_discovery_template` table.", spell_id); + if (SkillDiscoveryStore.find(int32(spellEntry->Id)) == SkillDiscoveryStore.end()) + TC_LOG_ERROR("sql.sql", "Spell (ID: %u) has got 100%% chance random discovery ability, but does not have data in the `skill_discovery_template` table.", spellEntry->Id); } TC_LOG_INFO("server.loading", ">> Loaded %u skill discovery definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); diff --git a/src/server/game/Skills/SkillExtraItems.cpp b/src/server/game/Skills/SkillExtraItems.cpp index 2b3ed8da563..8737586a5c3 100644 --- a/src/server/game/Skills/SkillExtraItems.cpp +++ b/src/server/game/Skills/SkillExtraItems.cpp @@ -71,14 +71,14 @@ void LoadSkillPerfectItemTable() uint32 spellId = fields[0].GetUInt32(); - if (!sSpellMgr->GetSpellInfo(spellId)) + if (!sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u has a non-existing spell id in the `skill_perfect_item_template`!", spellId); continue; } uint32 requiredSpecialization = fields[1].GetUInt32(); - if (!sSpellMgr->GetSpellInfo(requiredSpecialization)) + if (!sSpellMgr->GetSpellInfo(requiredSpecialization, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u has a non-existing required specialization spell id %u in the `skill_perfect_item_template`!", spellId, requiredSpecialization); continue; @@ -158,14 +158,14 @@ void LoadSkillExtraItemTable() uint32 spellId = fields[0].GetUInt32(); - if (!sSpellMgr->GetSpellInfo(spellId)) + if (!sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Skill specialization %u has a non-existing spell id in the `skill_extra_item_template`!", spellId); continue; } uint32 requiredSpecialization = fields[1].GetUInt32(); - if (!sSpellMgr->GetSpellInfo(requiredSpecialization)) + if (!sSpellMgr->GetSpellInfo(requiredSpecialization, DIFFICULTY_NONE)) { TC_LOG_ERROR("sql.sql", "Skill specialization %u has a non-existing required specialization spell id %u in the `skill_extra_item_template`!", spellId, requiredSpecialization); continue; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index ae1c88099bd..aef183d8b97 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -563,7 +563,7 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]= AuraEffect::AuraEffect(Aura* base, uint32 effIndex, int32 *baseAmount, Unit* caster) : m_base(base), m_spellInfo(base->GetSpellInfo()), -_effectInfo(base->GetSpellEffectInfo(effIndex)), +_effectInfo(m_spellInfo->GetEffect(effIndex)), m_baseAmount(baseAmount ? *baseAmount : _effectInfo->CalcBaseValue(caster, base->GetType() == UNIT_AURA_TYPE ? base->GetOwner()->ToUnit() : nullptr, base->GetCastItemId(), base->GetCastItemLevel())), m_damage(0), m_critChance(0.0f), m_donePct(1.0f), m_spellmod(NULL), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex), @@ -1216,7 +1216,7 @@ bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventIn { // Don't proc extra attacks while already processing extra attack spell uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; - if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) + if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) if (aurApp->GetTarget()->m_extraAttacks && triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) return false; break; @@ -1359,7 +1359,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (itr->first == spellId || itr->first == spellId2 || itr->first == spellId3 || itr->first == spellId4) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE); if (!spellInfo || !(spellInfo->IsPassive() || spellInfo->HasAttribute(SPELL_ATTR0_HIDDEN_CLIENTSIDE))) continue; @@ -1735,7 +1735,7 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo if (modelid > 0) { - SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm()); + SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm(), GetBase()->GetCastDifficulty()); if (!transformSpellInfo || !GetSpellInfo()->IsPositive()) target->SetDisplayId(modelid); } @@ -1828,7 +1828,7 @@ void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, if (apply) { // update active transform spell only when transform not set or not overwriting negative by positive case - SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm()); + SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->getTransForm(), GetBase()->GetCastDifficulty()); if (!transformSpellInfo || !GetSpellInfo()->IsPositive() || transformSpellInfo->IsPositive()) { target->setTransForm(GetId()); @@ -2550,7 +2550,7 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo } //some spell has one aura of mount and one of vehicle - for (SpellEffectInfo const* effect : GetBase()->GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffects()) if (effect && effect->Effect == SPELL_EFFECT_SUMMON && effect->MiscValue == GetMiscValue()) displayId = 0; } @@ -4688,10 +4688,10 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool uint32 spellId = 24659; if (apply && caster) { - SpellInfo const* spell = sSpellMgr->AssertSpellInfo(spellId); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(spellId, GetBase()->GetCastDifficulty()); for (uint32 i = 0; i < spell->StackAmount; ++i) - caster->CastSpell(target, spell->Id, true, NULL, NULL, GetCasterGUID()); + caster->CastSpell(target, spell, true, NULL, NULL, GetCasterGUID()); break; } target->RemoveAurasDueToSpell(spellId); @@ -4703,9 +4703,9 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool uint32 spellId = 24662; if (apply && caster) { - SpellInfo const* spell = sSpellMgr->AssertSpellInfo(spellId); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(spellId, GetBase()->GetCastDifficulty()); for (uint32 i = 0; i < spell->StackAmount; ++i) - caster->CastSpell(target, spell->Id, true, NULL, NULL, GetCasterGUID()); + caster->CastSpell(target, spell, true, NULL, NULL, GetCasterGUID()); break; } target->RemoveAurasDueToSpell(spellId); @@ -4964,11 +4964,11 @@ void AuraEffect::HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, boo Unit* target = aurApp->GetTarget(); uint32 triggeredSpellId = GetSpellEffectInfo()->TriggerSpell; - SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggeredSpellId); + SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggeredSpellId, GetBase()->GetCastDifficulty()); if (!triggeredSpellInfo) return; - Unit* caster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, target->GetMap()->GetDifficultyID()) ? GetCaster() : target; + Unit* caster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCaster() : target; if (!caster) return; @@ -4984,13 +4984,13 @@ void AuraEffect::HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, boo } else { - ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, caster->GetMap()->GetDifficultyID()) ? GetCasterGUID() : target->GetGUID(); + ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target->GetGUID(); target->RemoveAura(triggeredSpellId, casterGUID, 0, aurApp->GetRemoveMode()); } } else if (mode & AURA_EFFECT_HANDLE_REAPPLY && apply) { - ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, caster->GetMap()->GetDifficultyID()) ? GetCasterGUID() : target->GetGUID(); + ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target->GetGUID(); // change the stack amount to be equal to stack amount of our aura if (Aura* triggeredAura = target->GetAura(triggeredSpellId, casterGUID)) triggeredAura->ModStackAmount(GetBase()->GetStackAmount() - triggeredAura->GetStackAmount()); @@ -5259,7 +5259,7 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) // generic casting code with custom spells and target/caster customs uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; - SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId); + SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty()); SpellInfo const* auraSpellInfo = GetSpellInfo(); uint32 auraId = auraSpellInfo->Id; @@ -5519,11 +5519,11 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) } // Reget trigger spell proto - triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId); + triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty()); if (triggeredSpellInfo) { - if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, target->GetMap()->GetDifficultyID()) ? caster : target) + if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target) { triggerCaster->CastSpell(target, triggeredSpellInfo, true, NULL, this); TC_LOG_DEBUG("spells", "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell %u Trigger %u", GetId(), triggeredSpellInfo->Id); @@ -5536,9 +5536,9 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) void AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick(Unit* target, Unit* caster) const { uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; - if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) + if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) { - if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, target->GetMap()->GetDifficultyID()) ? caster : target) + if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target) { int32 basepoints = GetAmount(); triggerCaster->CastCustomSpell(target, triggerSpellId, &basepoints, &basepoints, &basepoints, true, nullptr, this); @@ -5580,7 +5580,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const break; case 38772: // Grievous Wound { - if (SpellEffectInfo const* effect = GetSpellInfo()->GetEffect(DIFFICULTY_NONE, EFFECT_1)) + if (SpellEffectInfo const* effect = GetSpellInfo()->GetEffect(EFFECT_1)) { uint32 percent = effect->CalcValue(caster); if (!target->HealthBelowPct(percent)) @@ -5779,7 +5779,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), damage, GetId(), absorb); // SendSpellNonMeleeDamageLog expects non-absorbed/non-resisted damage - SpellNonMeleeDamage log(caster, target, GetId(), GetBase()->GetSpellXSpellVisualId(), GetSpellInfo()->GetSchoolMask(), GetBase()->GetCastGUID()); + SpellNonMeleeDamage log(caster, target, GetSpellInfo(), GetBase()->GetSpellXSpellVisualId(), GetSpellInfo()->GetSchoolMask(), GetBase()->GetCastGUID()); log.damage = damage; log.originalDamage = dmg; log.absorb = absorb; @@ -6090,7 +6090,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con SpellInfo const* spellProto = GetSpellInfo(); // maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG - SpellNonMeleeDamage damageInfo(caster, target, spellProto->Id, GetBase()->GetSpellXSpellVisualId(), spellProto->SchoolMask, GetBase()->GetCastGUID()); + SpellNonMeleeDamage damageInfo(caster, target, spellProto, GetBase()->GetSpellXSpellVisualId(), spellProto->SchoolMask, GetBase()->GetCastGUID()); // no SpellDamageBonus for burn mana caster->CalculateSpellDamageTaken(&damageInfo, int32(gain * dmgMultiplier), spellProto); @@ -6131,7 +6131,7 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve Unit* triggerTarget = eventInfo.GetProcTarget(); uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; - if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) + if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) { TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerSpellAuraProc: Triggering spell %u from aura %u proc", triggeredSpellInfo->Id, GetId()); triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, NULL, this); @@ -6146,7 +6146,7 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp Unit* triggerTarget = eventInfo.GetProcTarget(); uint32 triggerSpellId = GetSpellEffectInfo()->TriggerSpell; - if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) + if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) { int32 basepoints0 = GetAmount(); TC_LOG_DEBUG("spells", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Triggering spell %u with value %d from aura %u proc", triggeredSpellInfo->Id, basepoints0, GetId()); @@ -6166,7 +6166,7 @@ void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEv return; } - SpellNonMeleeDamage damageInfo(target, triggerTarget, GetId(), GetBase()->GetSpellXSpellVisualId(), GetSpellInfo()->SchoolMask, GetBase()->GetCastGUID()); + SpellNonMeleeDamage damageInfo(target, triggerTarget, GetSpellInfo(), GetBase()->GetSpellXSpellVisualId(), GetSpellInfo()->SchoolMask, GetBase()->GetCastGUID()); uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, GetSpellEffectInfo()); damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE, GetSpellEffectInfo()); target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellInfo()); @@ -6327,7 +6327,7 @@ void AuraEffect::HandleLinkedSummon(AuraApplication const* aurApp, uint8 mode, b return; Unit* target = aurApp->GetTarget(); - SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(GetSpellEffectInfo()->TriggerSpell); + SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(GetSpellEffectInfo()->TriggerSpell, GetBase()->GetCastDifficulty()); if (!triggerSpellInfo) return; @@ -6338,7 +6338,7 @@ void AuraEffect::HandleLinkedSummon(AuraApplication const* aurApp, uint8 mode, b else { std::vector<uint32> summonedEntries; - for (auto spellEffect : triggerSpellInfo->GetEffectsForDifficulty(target->FindMap()->GetDifficultyID())) + for (auto spellEffect : triggerSpellInfo->GetEffects()) if (spellEffect && spellEffect->Effect == SPELL_EFFECT_SUMMON) if (uint32 summonEntry = spellEffect->MiscValue) summonedEntries.push_back(summonEntry); diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 54f520b5e85..bc43ee19e9b 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -89,7 +89,7 @@ void AuraApplication::_InitFlags(Unit* caster, uint32 effMask) if (IsSelfcast() || !caster || !caster->IsFriendlyTo(GetTarget())) { bool negativeFound = false; - for (SpellEffectInfo const* effect : GetBase()->GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetBase()->GetSpellInfo()->GetEffects()) { if (effect && ((1 << effect->EffectIndex) & effMask) && !GetBase()->GetSpellInfo()->IsPositiveEffect(effect->EffectIndex)) { @@ -104,7 +104,7 @@ void AuraApplication::_InitFlags(Unit* caster, uint32 effMask) else { bool positiveFound = false; - for (SpellEffectInfo const* effect : GetBase()->GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetBase()->GetSpellInfo()->GetEffects()) { if (effect && ((1 << effect->EffectIndex) & effMask) && GetBase()->GetSpellInfo()->IsPositiveEffect(effect->EffectIndex)) { @@ -234,14 +234,14 @@ uint32 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint32 availab { case TYPEID_UNIT: case TYPEID_PLAYER: - for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(owner->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellProto->GetEffects()) { if (effect && effect->IsUnitOwnedAuraEffect()) effMask |= 1 << effect->EffectIndex; } break; case TYPEID_DYNAMICOBJECT: - for (SpellEffectInfo const* effect : spellProto->GetEffectsForDifficulty(owner->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellProto->GetEffects()) { if (effect && effect->Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) effMask |= 1 << effect->EffectIndex; @@ -255,7 +255,7 @@ uint32 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint32 availab return effMask & availableEffectMask; } -Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= nullptr*/, bool resetPeriodicTimer /*= true*/, ObjectGuid castItemGuid /*= ObjectGuid::Empty*/, uint32 castItemId /*= 0*/, int32 castItemLevel /*= -1*/) +Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 tryEffMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= nullptr*/, bool resetPeriodicTimer /*= true*/, ObjectGuid castItemGuid /*= ObjectGuid::Empty*/, uint32 castItemId /*= 0*/, int32 castItemLevel /*= -1*/) { ASSERT(spellproto); ASSERT(owner); @@ -281,10 +281,10 @@ Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, ObjectGuid cast return foundAura; } else - return Create(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); + return Create(spellproto, castId, effMask, owner, caster, castDifficulty, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); } -Aura* Aura::TryCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, ObjectGuid castItemGuid /*= ObjectGuid::Empty*/, uint32 castItemId /*= 0*/, int32 castItemLevel /*= -1*/) +Aura* Aura::TryCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 tryEffMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, ObjectGuid castItemGuid /*= ObjectGuid::Empty*/, uint32 castItemId /*= 0*/, int32 castItemLevel /*= -1*/) { ASSERT(spellproto); ASSERT(owner); @@ -294,10 +294,10 @@ Aura* Aura::TryCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 try if (!effMask) return nullptr; - return Create(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); + return Create(spellproto, castId, effMask, owner, caster, castDifficulty, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); } -Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel) +Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel) { ASSERT(effMask); ASSERT(spellproto); @@ -327,10 +327,10 @@ Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMas { case TYPEID_UNIT: case TYPEID_PLAYER: - aura = new UnitAura(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); + aura = new UnitAura(spellproto, castId, effMask, owner, caster, castDifficulty, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); break; case TYPEID_DYNAMICOBJECT: - aura = new DynObjAura(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); + aura = new DynObjAura(spellproto, castId, effMask, owner, caster, castDifficulty, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); break; default: ABORT(); @@ -343,8 +343,9 @@ Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMas return aura; } -Aura::Aura(SpellInfo const* spellproto, ObjectGuid castId, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel) : -m_spellInfo(spellproto), m_castGuid(castId), m_casterGuid(!casterGUID.IsEmpty() ? casterGUID : caster->GetGUID()), +Aura::Aura(SpellInfo const* spellproto, ObjectGuid castId, WorldObject* owner, Unit* caster, Difficulty castDifficulty, + Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel) : +m_spellInfo(spellproto), m_castDifficulty(castDifficulty), m_castGuid(castId), m_casterGuid(!casterGUID.IsEmpty() ? casterGUID : caster->GetGUID()), m_castItemGuid(castItem ? castItem->GetGUID() : castItemGuid), m_castItemId(castItem ? castItem->GetEntry() : castItemId), m_castItemLevel(castItemLevel), m_spellXSpellVisualId(caster ? caster->GetCastSpellXSpellVisualId(spellproto) : spellproto->GetSpellXSpellVisualId()), m_applyTime(time(NULL)), m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), @@ -353,9 +354,8 @@ m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEven m_procCooldown(std::chrono::steady_clock::time_point::min()), m_lastProcAttemptTime(std::chrono::steady_clock::now() - Seconds(10)), m_lastProcSuccessTime(std::chrono::steady_clock::now() - Seconds(120)) { - std::vector<SpellPowerEntry const*> powers = sDB2Manager.GetSpellPowers(GetId(), caster ? caster->GetMap()->GetDifficultyID() : DIFFICULTY_NONE); - for (SpellPowerEntry const* power : powers) - if (power->ManaPerSecond != 0 || power->PowerPctPerSecond > 0.0f) + for (SpellPowerEntry const* power : m_spellInfo->PowerCosts) + if (power && (power->ManaPerSecond != 0 || power->PowerPctPerSecond > 0.0f)) m_periodicCosts.push_back(power); if (!m_periodicCosts.empty()) @@ -376,24 +376,12 @@ AuraScript* Aura::GetScriptByName(std::string const& scriptName) const return nullptr; } -SpellEffectInfo const* Aura::GetSpellEffectInfo(uint32 index) const -{ - if (index >= _spelEffectInfos.size()) - return nullptr; - - return _spelEffectInfos[index]; -} - void Aura::_InitEffects(uint32 effMask, Unit* caster, int32 *baseAmount) { // shouldn't be in constructor - functions in AuraEffect::AuraEffect use polymorphism - _spelEffectInfos = m_spellInfo->GetEffectsForDifficulty(GetOwner()->GetMap()->GetDifficultyID()); - - ASSERT(!_spelEffectInfos.empty()); - - _effects.resize(GetSpellEffectInfos().size()); + _effects.resize(GetSpellInfo()->GetEffects().size()); - for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffects()) { if (effect && effMask & (1 << effect->EffectIndex)) _effects[effect->EffectIndex] = new AuraEffect(this, effect->EffectIndex, baseAmount ? baseAmount + effect->EffectIndex : NULL, caster); @@ -855,7 +843,7 @@ void Aura::SetCharges(uint8 charges) uint8 Aura::CalcMaxCharges(Unit* caster) const { uint32 maxProcCharges = m_spellInfo->ProcCharges; - if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId())) + if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetSpellInfo())) maxProcCharges = procEntry->Charges; if (caster) @@ -976,7 +964,7 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode /*= AURA_REMOVE_B bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const { uint32 count = 0; - for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffects()) if (effect && HasEffect(effect->EffectIndex) && AuraType(effect->ApplyAuraName) == auraType) ++count; @@ -985,7 +973,7 @@ bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const bool Aura::IsArea() const { - for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffects()) if (effect && HasEffect(effect->EffectIndex) && effect->IsAreaAuraEffect()) return true; @@ -1358,7 +1346,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b // check cooldown if (caster->GetTypeId() == TYPEID_PLAYER) { - if (caster->GetSpellHistory()->HasCooldown(aura->GetId())) + if (caster->GetSpellHistory()->HasCooldown(aura->GetSpellInfo())) { // This additional check is needed to add a minimal delay before cooldown in in effect // to allow all bubbles broken by a single damage source proc mana return @@ -1515,14 +1503,14 @@ bool Aura::CanStackWith(Aura const* existingAura) const if (IsPassive() && sameCaster && (m_spellInfo->IsDifferentRankOf(existingSpellInfo) || (m_spellInfo->Id == existingSpellInfo->Id && m_castItemGuid.IsEmpty()))) return false; - for (SpellEffectInfo const* effect : existingAura->GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : existingSpellInfo->GetEffects()) { // prevent remove triggering aura by triggered aura if (effect && effect->TriggerSpell == GetId()) return true; } - for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffects()) { // prevent remove triggered aura by triggering aura refresh if (effect && effect->TriggerSpell == existingAura->GetId()) @@ -1535,7 +1523,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const // * The minimap tracking list will only show a check mark next to the last skill activated // Sometimes this bugs out and doesn't switch the check mark. It has no effect on the actual tracking though. // * The minimap dots are yellow for both resources - if (m_spellInfo->HasAura(GetOwner()->GetMap()->GetDifficultyID(), SPELL_AURA_TRACK_RESOURCES) && existingSpellInfo->HasAura(GetOwner()->GetMap()->GetDifficultyID(), SPELL_AURA_TRACK_RESOURCES)) + if (m_spellInfo->HasAura(SPELL_AURA_TRACK_RESOURCES) && existingSpellInfo->HasAura(SPELL_AURA_TRACK_RESOURCES)) return sWorld->getBoolConfig(CONFIG_ALLOW_TRACK_BOTH_RESOURCES); // check spell specific stack rules @@ -1574,7 +1562,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const // check same periodic auras for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - SpellEffectInfo const* effect = GetSpellEffectInfo(i); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(i); if (!effect) continue; switch (effect->ApplyAuraName) @@ -1592,7 +1580,7 @@ bool Aura::CanStackWith(Aura const* existingAura) const case SPELL_AURA_OBS_MOD_HEALTH: case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: { - SpellEffectInfo const* existingEffect = GetSpellEffectInfo(i); + SpellEffectInfo const* existingEffect = m_spellInfo->GetEffect(i); // periodic auras which target areas are not allowed to stack this way (replenishment for example) if (effect->IsTargetingArea() || (existingEffect && existingEffect->IsTargetingArea())) break; @@ -1662,7 +1650,7 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf SetNeedClientUpdateForTargets(); } - SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()); + SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetSpellInfo()); ASSERT(procEntry); // cooldowns should be added to the whole aura (see 51698 area aura) @@ -1673,7 +1661,7 @@ void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInf uint32 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const { - SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetId()); + SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(GetSpellInfo()); // only auras with spell proc entry can trigger proc if (!procEntry) return 0; @@ -1692,7 +1680,7 @@ uint32 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo } // check don't break stealth attr present - if (m_spellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_MOD_STEALTH)) + if (m_spellInfo->HasAura(SPELL_AURA_MOD_STEALTH)) { if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) if (spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH)) @@ -2253,8 +2241,9 @@ void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraAppli } } -UnitAura::UnitAura(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel) - : Aura(spellproto, castId, owner, caster, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) +UnitAura::UnitAura(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, + int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel) + : Aura(spellproto, castId, owner, caster, castDifficulty, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) { m_AuraDRGroup = DIMINISHING_NONE; LoadScripts(); @@ -2289,7 +2278,7 @@ void UnitAura::Remove(AuraRemoveMode removeMode) void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* caster) { - for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffects()) { if (!effect || !HasEffect(effect->EffectIndex)) continue; @@ -2357,8 +2346,9 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* c } } -DynObjAura::DynObjAura(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel) - : Aura(spellproto, castId, owner, caster, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) +DynObjAura::DynObjAura(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, + int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel) + : Aura(spellproto, castId, owner, caster, castDifficulty, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) { LoadScripts(); ASSERT(GetDynobjOwner()); @@ -2387,7 +2377,7 @@ void DynObjAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* Unit* dynObjOwnerCaster = GetDynobjOwner()->GetCaster(); float radius = GetDynobjOwner()->GetRadius(); - for (SpellEffectInfo const* effect : GetSpellEffectInfos()) + for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffects()) { if (!effect || !HasEffect(effect->EffectIndex)) continue; diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 2d8bdb477a1..5b5e0001aa8 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -119,15 +119,16 @@ class TC_GAME_API Aura typedef std::map<ObjectGuid, AuraApplication*> ApplicationMap; static uint32 BuildEffectMaskForOwner(SpellInfo const* spellProto, uint32 availableEffectMask, WorldObject* owner); - static Aura* TryRefreshStackOrCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool* refresh = nullptr, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = ObjectGuid::Empty, uint32 castItemId = 0, int32 castItemLevel = -1); - static Aura* TryCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid castItemGuid = ObjectGuid::Empty, uint32 castItemId = 0, int32 castItemLevel = -1); - static Aura* Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); - Aura(SpellInfo const* spellproto, ObjectGuid castId, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); + static Aura* TryRefreshStackOrCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 tryEffMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool* refresh = nullptr, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = ObjectGuid::Empty, uint32 castItemId = 0, int32 castItemLevel = -1); + static Aura* TryCreate(SpellInfo const* spellproto, ObjectGuid castId, uint32 tryEffMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, ObjectGuid castItemGuid = ObjectGuid::Empty, uint32 castItemId = 0, int32 castItemLevel = -1); + static Aura* Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32* baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); + Aura(SpellInfo const* spellproto, ObjectGuid castId, WorldObject* owner, Unit* caster, Difficulty castDifficulty, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); void _InitEffects(uint32 effMask, Unit* caster, int32 *baseAmount); virtual ~Aura(); SpellInfo const* GetSpellInfo() const { return m_spellInfo; } uint32 GetId() const{ return GetSpellInfo()->Id; } + Difficulty GetCastDifficulty() const { return m_castDifficulty; } ObjectGuid GetCastGUID() const { return m_castGuid; } ObjectGuid GetCasterGUID() const { return m_casterGuid; } @@ -288,10 +289,7 @@ class TC_GAME_API Aura std::vector<AuraScript*> m_loadedScripts; - AuraEffectVector GetAuraEffects() const { return _effects; } - - SpellEffectInfoVector GetSpellEffectInfos() const { return _spelEffectInfos; } - SpellEffectInfo const* GetSpellEffectInfo(uint32 index) const; + AuraEffectVector const& GetAuraEffects() const { return _effects; } private: AuraScript* GetScriptByName(std::string const& scriptName) const; @@ -299,6 +297,7 @@ class TC_GAME_API Aura protected: SpellInfo const* const m_spellInfo; + Difficulty const m_castDifficulty; ObjectGuid const m_castGuid; ObjectGuid const m_casterGuid; ObjectGuid const m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted @@ -334,14 +333,13 @@ class TC_GAME_API Aura Unit::AuraApplicationList m_removedApplications; AuraEffectVector _effects; - SpellEffectInfoVector _spelEffectInfos; }; class TC_GAME_API UnitAura : public Aura { - friend Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); + friend Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); public: - UnitAura(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); + UnitAura(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); void _ApplyForTarget(Unit* target, Unit* caster, AuraApplication * aurApp) override; void _UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * aurApp) override; @@ -360,9 +358,9 @@ class TC_GAME_API UnitAura : public Aura class TC_GAME_API DynObjAura : public Aura { - friend Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); + friend Aura* Aura::Create(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); public: - DynObjAura(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); + DynObjAura(SpellInfo const* spellproto, ObjectGuid castId, uint32 effMask, WorldObject* owner, Unit* caster, Difficulty castDifficulty, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint32 castItemId, int32 castItemLevel); void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index ada40659922..f9c6b64e7f3 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -492,13 +492,10 @@ void SpellCastTargets::OutDebug() const TC_LOG_DEBUG("spells", "pitch: %f", m_pitch); } -SpellValue::SpellValue(Difficulty diff, SpellInfo const* proto, Unit const* caster) +SpellValue::SpellValue(SpellInfo const* proto, Unit const* caster) { - // todo 6.x - SpellEffectInfoVector effects = proto->GetEffectsForDifficulty(diff); - ASSERT(effects.size() <= MAX_SPELL_EFFECTS); memset(EffectBasePoints, 0, sizeof(EffectBasePoints)); - for (SpellEffectInfo const* effect : effects) + for (SpellEffectInfo const* effect : proto->GetEffects()) if (effect) EffectBasePoints[effect->EffectIndex] = effect->CalcBaseValue(caster, nullptr, 0, -1); @@ -523,10 +520,8 @@ protected: Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) : m_spellInfo(info), m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster), -m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo, caster)), _spellEvent(nullptr) +m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr) { - _effects = info->GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID()); - m_customError = SPELL_CUSTOM_ERROR_NONE; m_skipCheck = skipCheck; m_fromClient = false; @@ -751,7 +746,7 @@ void Spell::SelectSpellTargets() uint32 processedAreaEffectsMask = 0; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -846,10 +841,10 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar // targets for effect already selected if (effectMask & processedEffectMask) return; - if (SpellEffectInfo const* _effect = GetEffect(effIndex)) + if (SpellEffectInfo const* _effect = m_spellInfo->GetEffect(effIndex)) { // choose which targets we can select at once - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { //for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j) if (!effect || effect->EffectIndex <= uint32(effIndex)) @@ -1020,7 +1015,7 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar return; } - SpellEffectInfo const* effect = GetEffect(effIndex); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex); if (!effect) return; @@ -1155,7 +1150,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge std::list<WorldObject*> targets; SpellTargetObjectTypes objectType = targetType.GetObjectType(); SpellTargetCheckTypes selectionType = targetType.GetCheckType(); - SpellEffectInfo const* effect = GetEffect(effIndex); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex); if (!effect) return; @@ -1241,7 +1236,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge } std::list<WorldObject*> targets; - SpellEffectInfo const* effect = GetEffect(effIndex); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex); if (!effect) return; float radius = effect->CalcRadius(m_caster) * m_spellValue->RadiusMod; @@ -1286,7 +1281,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, effIndex)) { /// @todo fix this check - if (HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || HasEffect(SPELL_EFFECT_BIND)) + if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || m_spellInfo->HasEffect(SPELL_EFFECT_BIND)) dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId); else if (st->target_mapId == m_caster->GetMapId()) dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation); @@ -1334,7 +1329,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici } default: { - if (SpellEffectInfo const* effect = GetEffect(effIndex)) + if (SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex)) { float dist = effect->CalcRadius(m_caster); float angle = targetType.CalcDirectionAngle(); @@ -1393,7 +1388,7 @@ void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplici break; default: { - if (SpellEffectInfo const* effect = GetEffect(effIndex)) + if (SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex)) { float angle = targetType.CalcDirectionAngle(); float objSize = target->GetCombatReach(); @@ -1435,7 +1430,7 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT return; default: { - if (SpellEffectInfo const* effect = GetEffect(effIndex)) + if (SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex)) { float angle = targetType.CalcDirectionAngle(); float dist = effect->CalcRadius(m_caster); @@ -1527,7 +1522,7 @@ void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImpli void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask) { - SpellEffectInfo const* effect = GetEffect(effIndex); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex); if (!effect) return; @@ -1538,7 +1533,7 @@ void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTarg if (maxTargets > 1) { // mark damage multipliers as used - for (SpellEffectInfo const* eff : GetEffects()) + for (SpellEffectInfo const* eff : m_spellInfo->GetEffects()) if (eff && (effMask & (1 << eff->EffectIndex))) m_damageMultipliers[eff->EffectIndex] = 1.0f; m_applyMultiplierMask |= effMask; @@ -1599,7 +1594,7 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range) // limit max range to 300 yards, sometimes triggered spells can have 50000yds float bestDist = m_spellInfo->GetMaxRange(false); - if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(effect->TriggerSpell)) + if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(effect->TriggerSpell, GetCastDifficulty())) bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f)); std::list<WorldObject*>::const_iterator itr = targets.begin(); @@ -1658,7 +1653,7 @@ void Spell::SelectEffectTypeImplicitTargets(uint32 effIndex) { // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER /// @todo this is a workaround - target shouldn't be stored in target map for those spells - SpellEffectInfo const* effect = GetEffect(effIndex); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex); if (!effect) return; switch (effect->Effect) @@ -2035,7 +2030,7 @@ class ProcReflectDelayed : public BasicEvent void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/) { uint32 validEffectMask = 0; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex)) != 0 && CheckEffectTarget(target, effect, losPosition)) validEffectMask |= 1 << effect->EffectIndex; @@ -2050,7 +2045,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= return; // Check for effect immune skip if immuned - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && target->IsImmunedToSpellEffect(m_spellInfo, effect->EffectIndex, m_caster)) effectMask &= ~(1 << effect->EffectIndex); @@ -2133,7 +2128,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= void Spell::AddGOTarget(GameObject* go, uint32 effectMask) { uint32 validEffectMask = 0; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex)) != 0 && CheckEffectTarget(go, effect)) validEffectMask |= 1 << effect->EffectIndex; @@ -2191,7 +2186,7 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask) void Spell::AddItemTarget(Item* item, uint32 effectMask) { uint32 validEffectMask = 0; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex)) != 0 && CheckEffectTarget(item, effect)) validEffectMask |= 1 << effect->EffectIndex; @@ -2240,7 +2235,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { uint32 farMask = 0; // create far target mask - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && effect->IsFarUnitTargetEffect()) if ((1 << effect->EffectIndex) & mask) farMask |= (1 << effect->EffectIndex); @@ -2255,7 +2250,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // do far effects on the unit // can't use default call because of threading, do stuff as fast as possible - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (farMask & (1 << effect->EffectIndex))) HandleEffects(unit, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); return; @@ -2415,7 +2410,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) else if (m_damage > 0) { // Fill base damage struct (unitTarget - is real spell target) - SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_SpellVisual, m_spellSchoolMask, m_castId); + SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_SpellVisual, m_spellSchoolMask, m_castId); // Check damage immunity if (unitTarget->IsImmunedToDamage(m_spellInfo)) @@ -2457,7 +2452,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) else { // Fill base damage struct (unitTarget - is real spell target) - SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_SpellVisual, m_spellSchoolMask); + SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_SpellVisual, m_spellSchoolMask); hitMask |= createProcHitMask(&damageInfo, missInfo); // Do triggers for unit if (canEffectTrigger) @@ -2526,7 +2521,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) // disable effects to which unit is immune SpellMissInfo returnVal = SPELL_MISS_IMMUNE; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex))) if (unit->IsImmunedToSpellEffect(m_spellInfo, effect->EffectIndex, m_caster)) effectMask &= ~(1 << effect->EffectIndex); @@ -2579,7 +2574,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) } uint32 aura_effmask = 0; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex) && effect->IsUnitOwnedAuraEffect())) aura_effmask |= 1 << effect->EffectIndex; @@ -2603,7 +2598,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) if (m_originalCaster) { int32 basePoints[MAX_SPELL_EFFECTS]; - for (SpellEffectInfo const* auraSpellEffect : GetEffects()) + for (SpellEffectInfo const* auraSpellEffect : m_spellInfo->GetEffects()) if (auraSpellEffect) basePoints[auraSpellEffect->EffectIndex] = (m_spellValue->CustomBasePointsMask & (1 << auraSpellEffect->EffectIndex)) ? m_spellValue->EffectBasePoints[auraSpellEffect->EffectIndex] : @@ -2612,7 +2607,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) bool refresh = false; bool const resetPeriodicTimer = !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER); m_spellAura = Aura::TryRefreshStackOrCreate(m_spellInfo, m_castId, effectMask, unit, - m_originalCaster, basePoints, + m_originalCaster, GetCastDifficulty(), basePoints, m_CastItem, ObjectGuid::Empty, &refresh, resetPeriodicTimer, ObjectGuid::Empty, m_castItemEntry, m_castItemLevel); if (m_spellAura) { @@ -2647,7 +2642,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) { m_spellAura->Remove(); bool found = false; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex) && effect->Effect != SPELL_EFFECT_APPLY_AURA)) found = true; if (!found) @@ -2668,7 +2663,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) { int32 origDuration = duration; duration = 0; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect) if (AuraEffect const* eff = m_spellAura->GetEffect(effect->EffectIndex)) if (int32 period = eff->GetPeriod()) // period is hastened by UNIT_MOD_CAST_SPEED @@ -2691,7 +2686,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) } } - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex))) HandleEffects(unit, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); @@ -2764,7 +2759,7 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo* target) PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(SPELL_MISS_NONE); - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex))) HandleEffects(NULL, NULL, go, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); @@ -2784,7 +2779,7 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo* target) PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(SPELL_MISS_NONE); - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (effectMask & (1 << effect->EffectIndex))) HandleEffects(NULL, target->item, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); @@ -2801,7 +2796,7 @@ bool Spell::UpdateChanneledTargetList() uint32 channelTargetEffectMask = m_channelTargetEffectMask; uint32 channelAuraMask = 0; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) channelAuraMask |= 1 << effect->EffectIndex; @@ -2998,7 +2993,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && m_spellInfo->IsBreakingStealth()) { m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST); - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && effect->GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT) { m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_SPELL_ATTACK); @@ -3493,7 +3488,7 @@ void Spell::_handle_immediate_phase() PrepareScriptHitHandlers(); // handle effects with SPELL_EFFECT_HANDLE_HIT mode - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { // don't do anything for empty effect if (!effect || !effect->IsEffect()) @@ -3521,7 +3516,7 @@ void Spell::_handle_finish_phase() m_caster->m_playerMovingMe->GainSpellComboPoints(m_comboPointGain); } - if (m_caster->m_extraAttacks && HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + if (m_caster->m_extraAttacks && m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) { if (Unit* victim = ObjectAccessor::GetUnit(*m_caster, m_targets.GetOrigUnitTargetGUID())) m_caster->HandleProcExtraAttackFor(victim); @@ -3572,7 +3567,7 @@ void Spell::update(uint32 difftime) // check if the player caster has moved before the spell finished // with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect - SpellEffectInfo const* effect = GetEffect(EFFECT_0); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(EFFECT_0); if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) && m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) && ((effect && effect->Effect != SPELL_EFFECT_STUCK) || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) && @@ -3678,7 +3673,7 @@ void Spell::finish(bool ok) { // Unsummon statue uint32 spell = m_caster->m_unitData->CreatedBySpell; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell, GetCastDifficulty()); if (spellInfo && spellInfo->IconFileDataId == 134230) { TC_LOG_DEBUG("spells", "Statue %s is unsummoned in spell %d finish", m_caster->GetGUID().ToString().c_str(), m_spellInfo->Id); @@ -3818,7 +3813,7 @@ inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo cons else { uint32 item = 0; - for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : spellInfo->GetEffects()) if (effect->ItemType) item = effect->ItemType; ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item); @@ -4114,7 +4109,7 @@ void Spell::SendSpellGo() castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list } - if (HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) + if (m_spellInfo->HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list if (m_targets.HasTraj()) @@ -4290,7 +4285,7 @@ void Spell::SendSpellExecuteLog() spellExecuteLog.Caster = m_caster->GetGUID(); spellExecuteLog.SpellID = m_spellInfo->Id; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -4803,7 +4798,7 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT gameObjTarget = pGOTarget; destTarget = &m_destTargets[i]._position; - effectInfo = GetEffect(i); + effectInfo = m_spellInfo->GetEffect(i); if (!effectInfo) { TC_LOG_ERROR("spells", "Spell: %u HandleEffects at EffectIndex: %u missing effect", m_spellInfo->Id, i); @@ -4950,7 +4945,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->isMoving() && (!m_caster->IsCharmed() || !m_caster->GetCharmerGUID().IsCreature()) && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo)) { // skip stuck spell to allow use it in falling case and apply spell limitations at movement - SpellEffectInfo const* effect = GetEffect(EFFECT_0); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(EFFECT_0); if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || (effect && effect->Effect != SPELL_EFFECT_STUCK)) && (IsAutoRepeat() || m_spellInfo->HasAuraInterruptFlag(AURA_INTERRUPT_FLAG_NOT_SEATED))) return SPELL_FAILED_MOVING; @@ -5051,7 +5046,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint } // check pet presence - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (effect && effect->TargetA.GetTarget() == TARGET_UNIT_PET) { @@ -5144,7 +5139,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint if (castResult != SPELL_CAST_OK) return castResult; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -5181,7 +5176,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint if (!pet) return SPELL_FAILED_NO_PET; - SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell); + SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell, DIFFICULTY_NONE); if (!learn_spellproto) return SPELL_FAILED_NOT_KNOWN; @@ -5212,7 +5207,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint if (!pet || pet->GetOwner() != m_caster) return SPELL_FAILED_BAD_TARGETS; - SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell); + SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell, DIFFICULTY_NONE); if (!learn_spellproto) return SPELL_FAILED_NOT_KNOWN; @@ -5645,7 +5640,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint } } - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -5704,7 +5699,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint } case SPELL_AURA_MOUNTED: { - if (m_caster->IsInWater() && m_spellInfo->HasAura(m_caster->GetMap()->GetDifficultyID(), SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) + if (m_caster->IsInWater() && m_spellInfo->HasAura(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) return SPELL_FAILED_ONLY_ABOVEWATER; // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells @@ -6069,7 +6064,7 @@ bool Spell::CanAutoCast(Unit* target) ObjectGuid targetguid = target->GetGUID(); // check if target already has the same or a more powerful aura - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -6300,7 +6295,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 / { // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example SpellCastResult failReason = SPELL_CAST_OK; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster if (!effect || effect->TargetA.GetTarget() == TARGET_UNIT_PET) @@ -6456,7 +6451,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 / } // special checks for spell effects - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -6491,7 +6486,7 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 / player->SendEquipError(msg, nullptr, nullptr, effect->ItemType); return SPELL_FAILED_DONT_REPORT; } - else if (SpellEffectInfo const* efi = GetEffect(EFFECT_1)) + else if (SpellEffectInfo const* efi = m_spellInfo->GetEffect(EFFECT_1)) player->CastSpell(m_caster, efi->CalcValue(), false); // move this to anywhere return SPELL_FAILED_DONT_REPORT; } @@ -6925,7 +6920,7 @@ bool Spell::UpdatePointers() WorldObject* transport = NULL; // update effect destinations (in case of moved transport dest target) - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -6959,6 +6954,11 @@ CurrentSpellTypes Spell::GetCurrentContainer() const return CURRENT_GENERIC_SPELL; } +Difficulty Spell::GetCastDifficulty() const +{ + return m_caster->GetMap()->GetDifficultyID(); +} + bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const* effect, Position const* losPosition) const { if (!effect->IsEffect()) @@ -7265,7 +7265,7 @@ bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const void Spell::HandleLaunchPhase() { // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { // don't do anything for empty effect if (!effect || !effect->IsEffect()) @@ -7275,7 +7275,7 @@ void Spell::HandleLaunchPhase() } float multiplier[MAX_SPELL_EFFECTS]; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) if (effect && (m_applyMultiplierMask & (1 << effect->EffectIndex))) multiplier[effect->EffectIndex] = effect->CalcDamageMultiplier(m_originalCaster, this); @@ -7307,7 +7307,7 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) if (!unit) return; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (effect && (targetInfo.effectMask & (1<<effect->EffectIndex))) { @@ -7356,7 +7356,7 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk if (!lockInfo) return SPELL_FAILED_BAD_TARGETS; - SpellEffectInfo const* effect = GetEffect(effIndex); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex); if (!effect) return SPELL_FAILED_BAD_TARGETS; // no idea about correct error @@ -7691,7 +7691,7 @@ bool Spell::CanExecuteTriggersOnHit(uint32 effMask, SpellInfo const* triggeredBy { bool only_on_caster = (triggeredByAura && (triggeredByAura->HasAttribute(SPELL_ATTR4_PROC_ONLY_ON_CASTER))); // If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a cast spell with TARGET_UNIT_CASTER - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (effect && ((effMask & (1 << effect->EffectIndex)) && (!only_on_caster || (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER)))) return true; @@ -7710,7 +7710,7 @@ void Spell::PrepareTriggersExecutedOnHit() if (!aurEff->IsAffectingSpell(m_spellInfo)) continue; - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(aurEff->GetSpellEffectInfo()->TriggerSpell)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(aurEff->GetSpellEffectInfo()->TriggerSpell, GetCastDifficulty())) { // calculate the chance using spell base amount, because aura amount is not updated on combo-points change // this possibly needs fixing @@ -7802,16 +7802,6 @@ void Spell::CancelGlobalCooldown() m_caster->GetSpellHistory()->CancelGlobalCooldown(m_spellInfo); } -bool Spell::HasEffect(SpellEffectName effect) const -{ - for (SpellEffectInfo const* eff : GetEffects()) - { - if (eff && eff->IsEffect(effect)) - return true; - } - return false; -} - namespace Trinity { diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index b8b72b5dcfc..e4ed1464a9f 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -297,7 +297,7 @@ class TC_GAME_API SpellCastTargets struct SpellValue { - explicit SpellValue(Difficulty diff, SpellInfo const* proto, Unit const* caster); + explicit SpellValue(SpellInfo const* proto, Unit const* caster); int32 EffectBasePoints[MAX_SPELL_EFFECTS]; uint32 CustomBasePointsMask; uint32 MaxAffectedTargets; @@ -677,6 +677,7 @@ class TC_GAME_API Spell Unit* GetCaster() const { return m_caster; } Unit* GetOriginalCaster() const { return m_originalCaster; } SpellInfo const* GetSpellInfo() const { return m_spellInfo; } + Difficulty GetCastDifficulty() const; std::vector<SpellPowerCost> const& GetPowerCost() const { return m_powerCost; } bool UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc) @@ -685,17 +686,6 @@ class TC_GAME_API Spell void SetSpellValue(SpellValueMod mod, int32 value); - std::vector<SpellEffectInfo const*> const& GetEffects() const { return _effects; } - SpellEffectInfo const* GetEffect(uint32 index) const - { - if (index >= _effects.size()) - return nullptr; - - return _effects[index]; - } - - bool HasEffect(SpellEffectName effect) const; - Spell** m_selfContainer; // pointer to our spell container (if applicable) SpellInfo const* GetTriggeredByAuraSpell() const { return m_triggeredByAuraSpell; } @@ -905,8 +895,6 @@ class TC_GAME_API Spell Spell(Spell const& right) = delete; Spell& operator=(Spell const& right) = delete; - - std::vector<SpellEffectInfo const*> _effects; }; namespace Trinity diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index e7d78a0ec57..a9fa7bfee03 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -429,7 +429,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) DamageInfo damageInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK); m_caster->CalcAbsorbResist(damageInfo); - SpellNonMeleeDamage log(m_caster, unitTarget, m_spellInfo->Id, m_SpellVisual, m_spellInfo->GetSchoolMask(), m_castId); + SpellNonMeleeDamage log(m_caster, unitTarget, m_spellInfo, m_SpellVisual, m_spellInfo->GetSchoolMask(), m_castId); log.damage = damageInfo.GetDamage(); log.originalDamage = damage; log.absorb = damageInfo.GetAbsorb(); @@ -658,7 +658,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex /*effIndex*/) case 29284: { // Brittle Armor - SpellInfo const* spell = sSpellMgr->GetSpellInfo(24575); + SpellInfo const* spell = sSpellMgr->GetSpellInfo(24575, GetCastDifficulty()); if (!spell) return; @@ -670,7 +670,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex /*effIndex*/) case 29286: { // Mercurial Shield - SpellInfo const* spell = sSpellMgr->GetSpellInfo(26464); + SpellInfo const* spell = sSpellMgr->GetSpellInfo(26464, GetCastDifficulty()); if (!spell) return; @@ -703,7 +703,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex /*effIndex*/) } // normal case - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id, GetCastDifficulty()); if (!spellInfo) { TC_LOG_ERROR("spells.effecttriggerspell", "Spell::EffectTriggerSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id); @@ -713,13 +713,13 @@ void Spell::EffectTriggerSpell(SpellEffIndex /*effIndex*/) SpellCastTargets targets; if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET) { - if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficultyID())) + if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo)) return; targets.SetUnitTarget(unitTarget); } else //if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH) { - if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficultyID()) && (effectInfo->GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK)) + if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) && (effectInfo->GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK)) return; if (spellInfo->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION) @@ -753,7 +753,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex /*effIndex*/) uint32 triggered_spell_id = effectInfo->TriggerSpell; // normal case - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id, GetCastDifficulty()); if (!spellInfo) { TC_LOG_ERROR("spells.effecttrigermissilespell", "Spell::EffectTriggerMissileSpell spell %u tried to trigger unknown spell %u.", m_spellInfo->Id, triggered_spell_id); @@ -763,13 +763,13 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex /*effIndex*/) SpellCastTargets targets; if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET) { - if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficultyID())) + if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo)) return; targets.SetUnitTarget(unitTarget); } else //if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT) { - if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficultyID()) && (effectInfo->GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK)) + if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) && (effectInfo->GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK)) return; if (spellInfo->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION) @@ -803,7 +803,7 @@ void Spell::EffectForceCast(SpellEffIndex /*effIndex*/) uint32 triggered_spell_id = effectInfo->TriggerSpell; // normal case - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id, GetCastDifficulty()); if (!spellInfo) { @@ -855,7 +855,7 @@ void Spell::EffectTriggerRitualOfSummoning(SpellEffIndex /*effIndex*/) return; uint32 triggered_spell_id = effectInfo->TriggerSpell; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id, GetCastDifficulty()); if (!spellInfo) { @@ -1504,7 +1504,7 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex) return; } - if (Aura* aura = Aura::TryCreate(m_spellInfo, m_castId, MAX_EFFECT_MASK, dynObj, caster, &m_spellValue->EffectBasePoints[0], nullptr, ObjectGuid::Empty, ObjectGuid::Empty, m_castItemEntry, m_castItemLevel)) + if (Aura* aura = Aura::TryCreate(m_spellInfo, m_castId, MAX_EFFECT_MASK, dynObj, caster, GetCastDifficulty(), &m_spellValue->EffectBasePoints[0], nullptr, ObjectGuid::Empty, ObjectGuid::Empty, m_castItemEntry, m_castItemLevel)) { m_spellAura = aura; m_spellAura->_RegisterForTargets(); @@ -2051,8 +2051,8 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) int32 basePoints = effectInfo->CalcValue(); if (basePoints > MAX_VEHICLE_SEATS) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(basePoints); - if (spellInfo && spellInfo->HasAura(m_originalCaster->GetMap()->GetDifficultyID(), SPELL_AURA_CONTROL_VEHICLE)) + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(basePoints, GetCastDifficulty()); + if (spellInfo && spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE)) spellId = spellInfo->Id; } @@ -2711,7 +2711,7 @@ void Spell::EffectLearnPetSpell(SpellEffIndex effIndex) if (!pet) return; - SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effectInfo->TriggerSpell); + SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effectInfo->TriggerSpell, DIFFICULTY_NONE); if (!learn_spellproto) return; @@ -2767,7 +2767,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) // and handle all effects at once for (uint8 index = effIndex + 1; index < MAX_SPELL_EFFECTS; ++index) { - SpellEffectInfo const* effect = GetEffect(index); + SpellEffectInfo const* effect = m_spellInfo->GetEffect(index); if (!effect) continue; switch (effect->Effect) @@ -2852,7 +2852,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) // Blood Strike if (m_spellInfo->SpellFamilyFlags[0] & 0x400000) { - if (SpellEffectInfo const* effect = GetEffect(EFFECT_2)) + if (SpellEffectInfo const* effect = m_spellInfo->GetEffect(EFFECT_2)) { float bonusPct = effect->CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) / 2.0f; // Death Knight T8 Melee 4P Bonus @@ -2868,7 +2868,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) bool normalized = false; float weaponDamagePercentMod = 1.0f; - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -2914,7 +2914,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, addPctMods); // Sequence is important - for (SpellEffectInfo const* effect : GetEffects()) + for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) { if (!effect) continue; @@ -3344,8 +3344,8 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) return; // Effects for 58418 and 58420 are all DIFFICULTY_NONE so always valid - uint32 spellID = GetEffect(EFFECT_0)->CalcValue(); - uint32 questID = GetEffect(EFFECT_1)->CalcValue(); + uint32 spellID = m_spellInfo->GetEffect(EFFECT_0)->CalcValue(); + uint32 questID = m_spellInfo->GetEffect(EFFECT_1)->CalcValue(); if (unitTarget->ToPlayer()->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE) unitTarget->CastSpell(unitTarget, spellID, true); @@ -3395,7 +3395,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) { /// @todo a hack, range = 11, should after some time cast, otherwise too far m_caster->CastSpell(parent, 62496, true); - unitTarget->CastSpell(parent, GetEffect(EFFECT_0)->CalcValue()); // DIFFICULTY_NONE, so effect always valid + unitTarget->CastSpell(parent, m_spellInfo->GetEffect(EFFECT_0)->CalcValue()); // DIFFICULTY_NONE, so effect always valid } } } @@ -3678,7 +3678,7 @@ void Spell::EffectStuck(SpellEffIndex /*effIndex*/) player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation(), TELE_TO_SPELL); // Stuck spell trigger Hearthstone cooldown - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(8690); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(8690, GetCastDifficulty()); if (!spellInfo) return; Spell spell(player, spellInfo, TRIGGERED_FULL_MASK); @@ -4528,7 +4528,7 @@ void Spell::EffectDestroyAllTotems(SpellEffIndex /*effIndex*/) if (totem && totem->IsTotem()) { uint32 spell_id = totem->m_unitData->CreatedBySpell; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, GetCastDifficulty()); if (spellInfo) { std::vector<SpellPowerCost> costs = spellInfo->CalcPowerCost(m_caster, spellInfo->GetSchoolMask()); @@ -5363,7 +5363,7 @@ void Spell::EffectCastButtons(SpellEffIndex /*effIndex*/) if (!spell_id) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, GetCastDifficulty()); if (!spellInfo) continue; @@ -5374,7 +5374,7 @@ void Spell::EffectCastButtons(SpellEffIndex /*effIndex*/) continue; TriggerCastFlags triggerFlags = TriggerCastFlags(TRIGGERED_IGNORE_GCD | TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_CAST_DIRECTLY | TRIGGERED_DONT_REPORT_CAST_ERROR); - m_caster->CastSpell(m_caster, spell_id, triggerFlags); + m_caster->CastSpell(m_caster, spellInfo, triggerFlags); } } @@ -5475,7 +5475,7 @@ void Spell::EffectResurrectWithAura(SpellEffIndex effIndex) uint32 health = target->CountPctFromMaxHealth(damage); uint32 mana = CalculatePct(target->GetMaxPower(POWER_MANA), damage); uint32 resurrectAura = 0; - if (sSpellMgr->GetSpellInfo(effectInfo->TriggerSpell)) + if (sSpellMgr->GetSpellInfo(effectInfo->TriggerSpell, DIFFICULTY_NONE)) resurrectAura = effectInfo->TriggerSpell; if (resurrectAura && target->HasAura(resurrectAura)) diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index 06ef2e8eb96..dd6ccf991f2 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -19,6 +19,7 @@ #include "DatabaseEnv.h" #include "DB2Stores.h" #include "Item.h" +#include "Map.h" #include "ObjectMgr.h" #include "Pet.h" #include "PetPackets.h" @@ -44,7 +45,7 @@ struct SpellHistory::PersistenceHelper<Player> static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry) { *spellId = fields[0].GetUInt32(); - if (!sSpellMgr->GetSpellInfo(*spellId)) + if (!sSpellMgr->GetSpellInfo(*spellId, DIFFICULTY_NONE)) return false; cooldownEntry->SpellId = *spellId; @@ -96,7 +97,7 @@ struct SpellHistory::PersistenceHelper<Pet> static bool ReadCooldown(Field* fields, uint32* spellId, CooldownEntry* cooldownEntry) { *spellId = fields[0].GetUInt32(); - if (!sSpellMgr->GetSpellInfo(*spellId)) + if (!sSpellMgr->GetSpellInfo(*spellId, DIFFICULTY_NONE)) return false; cooldownEntry->SpellId = *spellId; @@ -273,7 +274,7 @@ bool SpellHistory::IsReady(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, bo if (IsSchoolLocked(spellInfo->GetSchoolMask())) return false; - if (HasCooldown(spellInfo->Id, itemId, ignoreCategoryCooldown)) + if (HasCooldown(spellInfo, itemId, ignoreCategoryCooldown)) return false; if (!HasCharge(spellInfo->ChargeCategoryId)) @@ -519,7 +520,7 @@ void SpellHistory::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId / player->SendDirectMessage(WorldPackets::Spells::CooldownEvent(player != _owner, categoryItr->second->SpellId).Write()); if (startCooldown) - StartCooldown(sSpellMgr->AssertSpellInfo(categoryItr->second->SpellId), itemId, spell); + StartCooldown(sSpellMgr->AssertSpellInfo(categoryItr->second->SpellId, _owner->GetMap()->GetDifficultyID()), itemId, spell); } player->SendDirectMessage(WorldPackets::Spells::CooldownEvent(player != _owner, spellInfo->Id).Write()); @@ -633,7 +634,7 @@ bool SpellHistory::HasCooldown(SpellInfo const* spellInfo, uint32 itemId /*= 0*/ bool SpellHistory::HasCooldown(uint32 spellId, uint32 itemId /*= 0*/, bool ignoreCategoryCooldown /*= false*/) const { - return HasCooldown(sSpellMgr->AssertSpellInfo(spellId), itemId, ignoreCategoryCooldown); + return HasCooldown(sSpellMgr->AssertSpellInfo(spellId, _owner->GetMap()->GetDifficultyID()), itemId, ignoreCategoryCooldown); } uint32 SpellHistory::GetRemainingCooldown(SpellInfo const* spellInfo) const @@ -693,7 +694,7 @@ void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTim spellCooldown.Flags = SPELL_COOLDOWN_FLAG_NONE; for (uint32 spellId : knownSpells) { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(spellId, _owner->GetMap()->GetDifficultyID()); if (spellInfo->IsCooldownStartedOnEvent()) continue; @@ -926,7 +927,7 @@ void SpellHistory::RestoreCooldownStateAfterDuel() // add all profession CDs created while in duel (if any) for (auto const& c : _spellCooldowns) { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(c.first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(c.first, DIFFICULTY_NONE); if (spellInfo->RecoveryTime > 10 * MINUTE * IN_MILLISECONDS || spellInfo->CategoryRecoveryTime > 10 * MINUTE * IN_MILLISECONDS) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 04134692877..d9c797b053c 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -400,36 +400,39 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 150 TARGET_UNIT_OWN_CRITTER }; -SpellEffectInfo::SpellEffectInfo(SpellInfo const* spellInfo, uint8 effIndex, SpellEffectEntry const* _effect) +SpellEffectInfo::SpellEffectInfo(SpellInfo const* spellInfo, SpellEffectEntry const* _effect) { + ASSERT(spellInfo); + ASSERT(_effect); + _spellInfo = spellInfo; - EffectIndex = _effect ? _effect->EffectIndex : effIndex; - Effect = _effect ? _effect->Effect : 0; - ApplyAuraName = _effect ? _effect->EffectAura : 0; - ApplyAuraPeriod = _effect ? _effect->EffectAuraPeriod : 0; - RealPointsPerLevel = _effect ? _effect->EffectRealPointsPerLevel : 0.0f; - BasePoints = _effect ? _effect->EffectBasePoints : 0; - PointsPerResource = _effect ? _effect->EffectPointsPerResource : 0.0f; - Amplitude = _effect ? _effect->EffectAmplitude : 0.0f; - ChainAmplitude = _effect ? _effect->EffectChainAmplitude : 0.0f; - BonusCoefficient = _effect ? _effect->EffectBonusCoefficient : 0.0f; - MiscValue = _effect ? _effect->EffectMiscValue[0] : 0; - MiscValueB = _effect ? _effect->EffectMiscValue[1] : 0; - Mechanic = Mechanics(_effect ? _effect->EffectMechanic : 0); - PositionFacing = _effect ? _effect->EffectPosFacing : 0.0f; - TargetA = SpellImplicitTargetInfo(_effect ? _effect->ImplicitTarget[0] : 0); - TargetB = SpellImplicitTargetInfo(_effect ? _effect->ImplicitTarget[1] : 0); - RadiusEntry = _effect && _effect->EffectRadiusIndex[0] ? sSpellRadiusStore.LookupEntry(_effect->EffectRadiusIndex[0]) : NULL; - MaxRadiusEntry = _effect && _effect->EffectRadiusIndex[1] ? sSpellRadiusStore.LookupEntry(_effect->EffectRadiusIndex[1]) : NULL; - ChainTargets = _effect ? _effect->EffectChainTargets : 0; - ItemType = _effect ? _effect->EffectItemType : 0; - TriggerSpell = _effect ? _effect->EffectTriggerSpell : 0; - SpellClassMask = _effect ? _effect->EffectSpellClassMask : flag128(); - BonusCoefficientFromAP = _effect ? _effect->BonusCoefficientFromAP : 0.0f; + EffectIndex = _effect->EffectIndex; + Effect = _effect->Effect; + ApplyAuraName = _effect->EffectAura; + ApplyAuraPeriod = _effect->EffectAuraPeriod; + RealPointsPerLevel = _effect->EffectRealPointsPerLevel; + BasePoints = _effect->EffectBasePoints; + PointsPerResource = _effect->EffectPointsPerResource; + Amplitude = _effect->EffectAmplitude; + ChainAmplitude = _effect->EffectChainAmplitude; + BonusCoefficient = _effect->EffectBonusCoefficient; + MiscValue = _effect->EffectMiscValue[0]; + MiscValueB = _effect->EffectMiscValue[1]; + Mechanic = Mechanics(_effect->EffectMechanic); + PositionFacing = _effect->EffectPosFacing; + TargetA = SpellImplicitTargetInfo(_effect->ImplicitTarget[0]); + TargetB = SpellImplicitTargetInfo(_effect->ImplicitTarget[1]); + RadiusEntry = sSpellRadiusStore.LookupEntry(_effect->EffectRadiusIndex[0]); + MaxRadiusEntry = sSpellRadiusStore.LookupEntry(_effect->EffectRadiusIndex[1]); + ChainTargets = _effect->EffectChainTargets; + ItemType = _effect->EffectItemType; + TriggerSpell = _effect->EffectTriggerSpell; + SpellClassMask = _effect->EffectSpellClassMask; + BonusCoefficientFromAP = _effect->BonusCoefficientFromAP; Scaling.Coefficient = _effect->Coefficient; Scaling.Variance = _effect->Variance; Scaling.ResourceCoefficient = _effect->ResourceCoefficient; - ImplicitTargetConditions = NULL; + ImplicitTargetConditions = nullptr; } bool SpellEffectInfo::IsEffect() const @@ -1090,22 +1093,25 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 271 SPELL_EFFECT_APPLY_AREA_AURA_PARTY_NONRANDOM }; -SpellInfo::SpellInfo(SpellInfoLoadHelper const& data, SpellEffectEntryMap const& effectsMap, SpellVisualMap&& visuals) - : _hasPowerDifficultyData(false) +SpellInfo::SpellInfo(SpellNameEntry const* spellName, ::Difficulty difficulty, SpellInfoLoadHelper const& data, SpellVisualVector&& visuals) { - Id = data.Entry->ID; + Id = spellName->ID; + Difficulty = difficulty; - for (SpellEffectEntryMap::value_type const& itr : effectsMap) + _effects.reserve(32); + for (SpellEffectEntry const* spellEffect : data.Effects) { - SpellEffectEntryVector const& effects = itr.second; - _effects[itr.first].resize(effects.size()); + if (!spellEffect) + continue; + + if (uint32(spellEffect->EffectIndex) >= _effects.size()) + _effects.resize(spellEffect->EffectIndex + 1); - for (size_t i = 0; i < effects.size(); ++i) - if (SpellEffectEntry const* effect = effects[i]) - _effects[itr.first][effect->EffectIndex] = new SpellEffectInfo(this, effect->EffectIndex, effect); + _effects[spellEffect->EffectIndex] = new SpellEffectInfo(this, spellEffect); } + _effects.shrink_to_fit(); - SpellName = data.Entry->Name; + SpellName = spellName->Name; // SpellMiscEntry SpellMiscEntry const* _misc = data.Misc; @@ -1136,9 +1142,6 @@ SpellInfo::SpellInfo(SpellInfoLoadHelper const& data, SpellEffectEntryMap const& ContentTuningId = _misc ? _misc->ContentTuningID : 0; _visuals = std::move(visuals); - // sort all visuals so that the ones without a condition requirement are last on the list - for (auto& visualPair : _visuals) - std::sort(visualPair.second.begin(), visualPair.second.end(), [](SpellXSpellVisualEntry const* first, SpellXSpellVisualEntry const* second) { return first->CasterPlayerConditionID > second->CasterPlayerConditionID; }); // SpellScalingEntry SpellScalingEntry const* _scaling = data.Scaling; @@ -1224,7 +1227,7 @@ SpellInfo::SpellInfo(SpellInfoLoadHelper const& data, SpellEffectEntryMap const& SpellLevel = _levels ? _levels->SpellLevel : 0; // SpellPowerEntry - PowerCosts = sDB2Manager.GetSpellPowers(Id, DIFFICULTY_NONE, &_hasPowerDifficultyData); + PowerCosts = data.Powers; // SpellReagentsEntry SpellReagentsEntry const* _reagents = data.Reagents; @@ -1271,9 +1274,9 @@ SpellInfo::~SpellInfo() void SpellInfo::_UnloadSpellEffects() { - for (SpellEffectInfoMap::value_type& i : _effects) - for (size_t j = 0; j < i.second.size(); ++j) - delete i.second[j]; + for (SpellEffectInfo const* effect : _effects) + delete effect; + _effects.clear(); } @@ -1282,88 +1285,53 @@ uint32 SpellInfo::GetCategory() const return CategoryId; } -bool SpellInfo::HasEffect(uint32 difficulty, SpellEffectName effect) const +bool SpellInfo::HasEffect(SpellEffectName effect) const { - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* eff : effects) - { + for (SpellEffectInfo const* eff : _effects) if (eff && eff->IsEffect(effect)) return true; - } - return false; -} -bool SpellInfo::HasEffect(SpellEffectName effect) const -{ - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) - { - for (SpellEffectInfo const* eff : itr->second) - { - if (eff && eff->IsEffect(effect)) - return true; - } - } return false; } -bool SpellInfo::HasAura(uint32 difficulty, AuraType aura) const +bool SpellInfo::HasAura(AuraType aura) const { - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* effect : effects) - { + for (SpellEffectInfo const* effect : _effects) if (effect && effect->IsAura(aura)) return true; - } + return false; } -bool SpellInfo::HasAreaAuraEffect(uint32 difficulty) const +bool SpellInfo::HasAreaAuraEffect() const { - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* effect : effects) - { + for (SpellEffectInfo const* effect : _effects) if (effect && effect->IsAreaAuraEffect()) return true; - } - return false; -} -bool SpellInfo::HasAreaAuraEffect() const -{ - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) - { - for (SpellEffectInfo const* effect : itr->second) - { - if (effect && effect->IsAreaAuraEffect()) - return true; - } - } return false; } bool SpellInfo::HasOnlyDamageEffects() const { - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + for (SpellEffectInfo const* effect : _effects) { - for (SpellEffectInfo const* effect : itr->second) + if (!effect) + continue; + + switch (effect->Effect) { - if (!effect) + case SPELL_EFFECT_WEAPON_DAMAGE: + case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: + case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: + case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: + case SPELL_EFFECT_SCHOOL_DAMAGE: + case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: + case SPELL_EFFECT_HEALTH_LEECH: + case SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT: continue; - - switch (effect->Effect) - { - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - case SPELL_EFFECT_SCHOOL_DAMAGE: - case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE: - case SPELL_EFFECT_HEALTH_LEECH: - case SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT: - continue; - default: - return false; - } + default: + return false; } } @@ -1372,25 +1340,10 @@ bool SpellInfo::HasOnlyDamageEffects() const bool SpellInfo::HasTargetType(::Targets target) const { - for (auto itr = _effects.begin(); itr != _effects.end(); ++itr) - { - for (SpellEffectInfo const* effect : itr->second) - { - if (effect && (effect->TargetA.GetTarget() == target || effect->TargetB.GetTarget() == target)) - return true; - } - } - return false; -} - -bool SpellInfo::HasTargetType(uint32 difficulty, ::Targets target) const -{ - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* effect : effects) - { + for (SpellEffectInfo const* effect : _effects) if (effect && (effect->TargetA.GetTarget() == target || effect->TargetB.GetTarget() == target)) return true; - } + return false; } @@ -1401,8 +1354,8 @@ bool SpellInfo::HasAnyAuraInterruptFlag() const bool SpellInfo::IsExplicitDiscovery() const { - SpellEffectInfo const* effect0 = GetEffect(DIFFICULTY_NONE, EFFECT_0); - SpellEffectInfo const* effect1 = GetEffect(DIFFICULTY_NONE, EFFECT_1); + SpellEffectInfo const* effect0 = GetEffect(EFFECT_0); + SpellEffectInfo const* effect1 = GetEffect(EFFECT_1); return ((effect0 && (effect0->Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM || effect0->Effect == SPELL_EFFECT_CREATE_LOOT)) && effect1 && effect1->Effect == SPELL_EFFECT_SCRIPT_EFFECT) @@ -1416,15 +1369,14 @@ bool SpellInfo::IsLootCrafting() const bool SpellInfo::IsQuestTame() const { - SpellEffectInfo const* effect0 = GetEffect(DIFFICULTY_NONE, EFFECT_0); - SpellEffectInfo const* effect1 = GetEffect(DIFFICULTY_NONE, EFFECT_1); + SpellEffectInfo const* effect0 = GetEffect(EFFECT_0); + SpellEffectInfo const* effect1 = GetEffect(EFFECT_1); return effect0 && effect1 && effect0->Effect == SPELL_EFFECT_THREAT && effect1->Effect == SPELL_EFFECT_APPLY_AURA && effect1->ApplyAuraName == SPELL_AURA_DUMMY; } -bool SpellInfo::IsProfession(uint32 difficulty) const +bool SpellInfo::IsProfession() const { - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* effect : effects) + for (SpellEffectInfo const* effect : _effects) { if (effect && effect->Effect == SPELL_EFFECT_SKILL) { @@ -1437,10 +1389,9 @@ bool SpellInfo::IsProfession(uint32 difficulty) const return false; } -bool SpellInfo::IsPrimaryProfession(uint32 difficulty) const +bool SpellInfo::IsPrimaryProfession() const { - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for(SpellEffectInfo const* effect : effects) + for (SpellEffectInfo const* effect : _effects) { if (effect && effect->Effect == SPELL_EFFECT_SKILL) { @@ -1453,9 +1404,9 @@ bool SpellInfo::IsPrimaryProfession(uint32 difficulty) const return false; } -bool SpellInfo::IsPrimaryProfessionFirstRank(uint32 difficulty) const +bool SpellInfo::IsPrimaryProfessionFirstRank() const { - return IsPrimaryProfession(difficulty) && GetRank() == 1; + return IsPrimaryProfession() && GetRank() == 1; } bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const @@ -1469,26 +1420,22 @@ bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const return false; } -bool SpellInfo::IsAffectingArea(uint32 difficulty) const +bool SpellInfo::IsAffectingArea() const { - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* effect : effects) - { + for (SpellEffectInfo const* effect : _effects) if (effect && effect->IsEffect() && (effect->IsTargetingArea() || effect->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) || effect->IsAreaAuraEffect())) return true; - } + return false; } // checks if spell targets are selected from area, doesn't include spell effects in check (like area wide auras for example) -bool SpellInfo::IsTargetingArea(uint32 difficulty) const +bool SpellInfo::IsTargetingArea() const { - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* effect : effects) - { + for (SpellEffectInfo const* effect : _effects) if (effect && effect->IsEffect() && effect->IsTargetingArea()) return true; - } + return false; } @@ -1497,7 +1444,7 @@ bool SpellInfo::NeedsExplicitUnitTarget() const return (GetExplicitTargetMask() & TARGET_FLAG_UNIT_MASK) != 0; } -bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell, uint32 difficulty) const +bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const { if (NeedsExplicitUnitTarget()) return true; @@ -1517,8 +1464,7 @@ bool SpellInfo::NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell, uin if (triggeringSpell->IsChanneled()) { uint32 mask = 0; - SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); - for (SpellEffectInfo const* effect : effects) + for (SpellEffectInfo const* effect : _effects) { if (!effect) continue; @@ -1557,8 +1503,7 @@ bool SpellInfo::IsStackableWithRanks() const return false; // All stance spells. if any better way, change it. - SpellEffectInfoVector effects = GetEffectsForDifficulty(DIFFICULTY_NONE); - for (SpellEffectInfo const* effect : effects) + for (SpellEffectInfo const* effect : _effects) { if (!effect) continue; @@ -1582,9 +1527,9 @@ bool SpellInfo::IsStackableWithRanks() const return true; } -bool SpellInfo::IsPassiveStackableWithRanks(uint32 difficulty) const +bool SpellInfo::IsPassiveStackableWithRanks() const { - return IsPassive() && !HasEffect(difficulty, SPELL_EFFECT_APPLY_AURA); + return IsPassive() && !HasEffect(SPELL_EFFECT_APPLY_AURA); } bool SpellInfo::IsMultiSlotAura() const @@ -1624,8 +1569,7 @@ bool SpellInfo::IsAllowingDeadTarget() const bool SpellInfo::IsGroupBuff() const { - SpellEffectInfoVector effects = GetEffectsForDifficulty(DIFFICULTY_NONE); - for (SpellEffectInfo const* effect : effects) + for (SpellEffectInfo const* effect : _effects) { if (!effect) continue; @@ -1778,7 +1722,7 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const if (!IsAffectedBySpellMods()) return false; - SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId); + SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId, Difficulty); if (!affectSpell) return false; @@ -2087,7 +2031,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a // aura limitations if (player) { - for (SpellEffectInfo const* effect : GetEffectsForDifficulty(player->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : _effects) { if (!effect || !effect->IsAura()) continue; @@ -2256,7 +2200,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta return SPELL_FAILED_TARGET_AURASTATE; if (unitTarget->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) - if (HasEffect(caster->GetMap()->GetDifficultyID(), SPELL_EFFECT_SELF_RESURRECT) || HasEffect(caster->GetMap()->GetDifficultyID(), SPELL_EFFECT_RESURRECT)) + if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT)) return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED; if (HasAttribute(SPELL_ATTR8_BATTLE_RESURRECTION)) @@ -2314,7 +2258,7 @@ SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const if (vehicle) { uint16 checkMask = 0; - for (SpellEffectInfo const* effect : GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : _effects) { if (effect && effect->ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) { @@ -2325,7 +2269,7 @@ SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const } } - if (HasAura(caster->GetMap()->GetDifficultyID(), SPELL_AURA_MOUNTED)) + if (HasAura(SPELL_AURA_MOUNTED)) checkMask |= VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL; if (!checkMask) @@ -2339,7 +2283,7 @@ SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const // Can only summon uncontrolled minions/guardians when on controlled vehicle if (vehicleSeat->Flags & (VEHICLE_SEAT_FLAG_CAN_CONTROL | VEHICLE_SEAT_FLAG_UNK2)) { - for (SpellEffectInfo const* effect : GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : _effects) { if (!effect || effect->Effect != SPELL_EFFECT_SUMMON) continue; @@ -2384,14 +2328,11 @@ uint32 SpellInfo::GetAllEffectsMechanicMask() const uint32 mask = 0; if (Mechanic) mask |= 1 << Mechanic; - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) - { - for (SpellEffectInfo const* effect : itr->second) - { - if (effect && effect->IsEffect() && effect->Mechanic) - mask |= 1 << effect->Mechanic; - } - } + + for (SpellEffectInfo const* effect : _effects) + if (effect && effect->IsEffect() && effect->Mechanic) + mask |= 1 << effect->Mechanic; + return mask; } @@ -2400,14 +2341,10 @@ uint32 SpellInfo::GetEffectMechanicMask(uint32 effIndex) const uint32 mask = 0; if (Mechanic) mask |= 1 << Mechanic; - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) - { - for (SpellEffectInfo const* effect : itr->second) - { - if (effect && effect->EffectIndex == effIndex && effect->IsEffect() && effect->Mechanic) - mask |= 1 << effect->Mechanic; - } - } + + if (effIndex < _effects.size() && _effects[effIndex] && _effects[effIndex]->IsEffect() && _effects[effIndex]->Mechanic) + mask |= 1 << _effects[effIndex]->Mechanic; + return mask; } @@ -2416,24 +2353,23 @@ uint32 SpellInfo::GetSpellMechanicMaskByEffectMask(uint32 effectMask) const uint32 mask = 0; if (Mechanic) mask |= 1 << Mechanic; - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) - { - for (SpellEffectInfo const* effect : itr->second) - { - if (effect && (effectMask & (1 << effect->EffectIndex)) && effect->Mechanic) - mask |= 1 << effect->Mechanic; - } - } + + for (SpellEffectInfo const* effect : _effects) + if (effect && (effectMask & (1 << effect->EffectIndex)) && effect->Mechanic) + mask |= 1 << effect->Mechanic; + return mask; } -Mechanics SpellInfo::GetEffectMechanic(uint32 effIndex, uint32 difficulty) const +Mechanics SpellInfo::GetEffectMechanic(uint32 effIndex) const { - SpellEffectInfo const* effect = GetEffect(difficulty, effIndex); + SpellEffectInfo const* effect = GetEffect(effIndex); if (effect && effect->IsEffect() && effect->Mechanic) return Mechanics(effect->Mechanic); + if (Mechanic) return Mechanics(Mechanic); + return MECHANIC_NONE; } @@ -2514,10 +2450,9 @@ void SpellInfo::_LoadAuraState() return AURA_STATE_BLEEDING; if (GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) - for (SpellEffectInfo const* effect : itr->second) - if (effect && (effect->IsAura(SPELL_AURA_MOD_STUN) || effect->IsAura(SPELL_AURA_MOD_ROOT))) - return AURA_STATE_FROZEN; + for (SpellEffectInfo const* effect : _effects) + if (effect && (effect->IsAura(SPELL_AURA_MOD_STUN) || effect->IsAura(SPELL_AURA_MOD_ROOT))) + return AURA_STATE_FROZEN; switch (Id) { @@ -2550,27 +2485,24 @@ void SpellInfo::_LoadSpellSpecific() { bool food = false; bool drink = false; - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + for (SpellEffectInfo const* effect : _effects) { - for (SpellEffectInfo const* effect : itr->second) + if (!effect || !effect->IsAura()) + continue; + switch (effect->ApplyAuraName) { - if (!effect || !effect->IsAura()) - continue; - switch (effect->ApplyAuraName) - { - // Food + // Food case SPELL_AURA_MOD_REGEN: case SPELL_AURA_OBS_MOD_HEALTH: food = true; break; - // Drink + // Drink case SPELL_AURA_MOD_POWER_REGEN: case SPELL_AURA_OBS_MOD_POWER: drink = true; break; default: break; - } } } @@ -2609,7 +2541,7 @@ void SpellInfo::_LoadSpellSpecific() // Arcane brillance and Arcane intelect (normal check fails because of flags difference) if (SpellFamilyFlags[0] & 0x400) return SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE; - SpellEffectInfo const* effect = GetEffect(DIFFICULTY_NONE, EFFECT_0); + SpellEffectInfo const* effect = GetEffect(EFFECT_0); if (effect && (SpellFamilyFlags[0] & 0x1000000) && effect->ApplyAuraName == SPELL_AURA_MOD_CONFUSE) return SPELL_SPECIFIC_MAGE_POLYMORPH; @@ -2696,14 +2628,12 @@ void SpellInfo::_LoadSpellSpecific() break; } - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + for (SpellEffectInfo const* effect : _effects) { - for (SpellEffectInfo const* effect : itr->second) + if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) { - if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) + switch (effect->ApplyAuraName) { - switch (effect->ApplyAuraName) - { case SPELL_AURA_MOD_CHARM: case SPELL_AURA_MOD_POSSESS_PET: case SPELL_AURA_MOD_POSSESS: @@ -2713,11 +2643,10 @@ void SpellInfo::_LoadSpellSpecific() /// @workaround For non-stacking tracking spells (We need generic solution) if (Id == 30645) // Gas Cloud Tracking return SPELL_SPECIFIC_NORMAL; - /* fallthrough */ + /* fallthrough */ case SPELL_AURA_TRACK_RESOURCES: case SPELL_AURA_TRACK_STEALTHED: return SPELL_SPECIFIC_TRACKER; - } } } } @@ -2732,7 +2661,7 @@ void SpellInfo::_LoadSpellDiminishInfo() if (IsPositive()) return DIMINISHING_NONE; - if (HasAura(DIFFICULTY_NONE, SPELL_AURA_MOD_TAUNT)) + if (HasAura(SPELL_AURA_MOD_TAUNT)) return DIMINISHING_TAUNT; switch (Id) @@ -3459,15 +3388,12 @@ void SpellInfo::_LoadImmunityInfo() _allowedMechanicMask |= immuneInfo.MechanicImmuneMask; }; - for (auto const& effects : _effects) + for (SpellEffectInfo const* effect : _effects) { - for (SpellEffectInfo const* effect : effects.second) - { - if (!effect) - continue; + if (!effect) + continue; - loadImmunityInfoFn(const_cast<SpellEffectInfo*>(effect)); - } + loadImmunityInfoFn(const_cast<SpellEffectInfo*>(effect)); } if (HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED)) @@ -3570,7 +3496,7 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf if (!auraSpellInfo) return false; - for (SpellEffectInfo const* effectInfo : GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effectInfo : _effects) { if (!effectInfo) continue; @@ -3593,7 +3519,7 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf return true; bool immuneToAllEffects = true; - for (SpellEffectInfo const* auraSpellEffectInfo : auraSpellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* auraSpellEffectInfo : auraSpellInfo->GetEffects()) { if (!auraSpellEffectInfo) continue; @@ -3659,7 +3585,7 @@ bool SpellInfo::SpellCancelsAuraEffect(AuraEffect const* aurEff) const if (aurEff->GetSpellInfo()->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) return false; - for (SpellEffectInfo const* effectInfo : GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effectInfo : _effects) { if (!effectInfo) continue; @@ -3786,13 +3712,13 @@ uint32 SpellInfo::CalcCastTime(uint8 level, Spell* spell /*= NULL*/) const return (castTime > 0) ? uint32(castTime) : 0; } -uint32 SpellInfo::GetMaxTicks(uint32 difficulty) const +uint32 SpellInfo::GetMaxTicks() const { int32 DotDuration = GetDuration(); if (DotDuration == 0) return 1; - for (SpellEffectInfo const* effect : GetEffectsForDifficulty(difficulty)) + for (SpellEffectInfo const* effect : _effects) { if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) switch (effect->ApplyAuraName) @@ -3828,190 +3754,184 @@ uint32 SpellInfo::GetRecoveryTime() const std::vector<SpellPowerCost> SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, Spell* spell) const { std::vector<SpellPowerCost> costs; - auto collector = [this, caster, schoolMask, spell, &costs](std::vector<SpellPowerEntry const*> const& powers) + costs.reserve(MAX_POWERS_PER_SPELL); + int32 healthCost = 0; + + for (SpellPowerEntry const* power : PowerCosts) { - costs.reserve(powers.size()); - int32 healthCost = 0; + if (!power) + continue; + if (power->RequiredAuraSpellID && !caster->HasAura(power->RequiredAuraSpellID)) + continue; - for (SpellPowerEntry const* power : powers) + // Spell drain all exist power on cast (Only paladin lay of Hands) + if (HasAttribute(SPELL_ATTR1_DRAIN_ALL_POWER)) { - if (power->RequiredAuraSpellID && !caster->HasAura(power->RequiredAuraSpellID)) - continue; - - // Spell drain all exist power on cast (Only paladin lay of Hands) - if (HasAttribute(SPELL_ATTR1_DRAIN_ALL_POWER)) + // If power type - health drain all + if (power->PowerType == POWER_HEALTH) { - // If power type - health drain all - if (power->PowerType == POWER_HEALTH) - { - healthCost = caster->GetHealth(); - continue; - } - // Else drain all power - if (power->PowerType < MAX_POWERS) - { - SpellPowerCost cost; - cost.Power = Powers(power->PowerType); - cost.Amount = caster->GetPower(cost.Power); - costs.push_back(cost); - continue; - } - - TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", power->PowerType, Id); + healthCost = caster->GetHealth(); continue; } - - // Base powerCost - int32 powerCost = power->ManaCost; - // PCT cost from total amount - if (power->PowerCostPct) + // Else drain all power + if (power->PowerType < MAX_POWERS) { - switch (power->PowerType) - { - // health as power used - case POWER_HEALTH: - powerCost += int32(CalculatePct(caster->GetMaxHealth(), power->PowerCostPct)); - break; - case POWER_MANA: - powerCost += int32(CalculatePct(caster->GetCreateMana(), power->PowerCostPct)); - break; - case POWER_RAGE: - case POWER_FOCUS: - case POWER_ENERGY: - powerCost += int32(CalculatePct(caster->GetMaxPower(Powers(power->PowerType)), power->PowerCostPct)); - break; - case POWER_RUNES: - case POWER_RUNIC_POWER: - TC_LOG_DEBUG("spells", "CalculateManaCost: Not implemented yet!"); - break; - default: - TC_LOG_ERROR("spells", "CalculateManaCost: Unknown power type '%d' in spell %d", power->PowerType, Id); - continue; - } + SpellPowerCost cost; + cost.Power = Powers(power->PowerType); + cost.Amount = caster->GetPower(cost.Power); + costs.push_back(cost); + continue; } - if (power->PowerCostMaxPct) - healthCost += int32(CalculatePct(caster->GetMaxHealth(), power->PowerCostMaxPct)); - - int32 optionalCost = int32(power->OptionalCost); - optionalCost += caster->GetTotalAuraModifier(SPELL_AURA_MOD_ADDITIONAL_POWER_COST, [this, power](AuraEffect const* aurEff) -> bool - { - return aurEff->GetMiscValue() == power->PowerType - && aurEff->IsAffectingSpell(this); - }); + TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", power->PowerType, Id); + continue; + } - if (optionalCost) + // Base powerCost + int32 powerCost = power->ManaCost; + // PCT cost from total amount + if (power->PowerCostPct) + { + switch (power->PowerType) { - int32 remainingPower = caster->GetPower(Powers(power->PowerType)) - powerCost; - powerCost += RoundToInterval<int32>(remainingPower, 0, optionalCost); + // health as power used + case POWER_HEALTH: + powerCost += int32(CalculatePct(caster->GetMaxHealth(), power->PowerCostPct)); + break; + case POWER_MANA: + powerCost += int32(CalculatePct(caster->GetCreateMana(), power->PowerCostPct)); + break; + case POWER_RAGE: + case POWER_FOCUS: + case POWER_ENERGY: + powerCost += int32(CalculatePct(caster->GetMaxPower(Powers(power->PowerType)), power->PowerCostPct)); + break; + case POWER_RUNES: + case POWER_RUNIC_POWER: + TC_LOG_DEBUG("spells", "CalculateManaCost: Not implemented yet!"); + break; + default: + TC_LOG_ERROR("spells", "CalculateManaCost: Unknown power type '%d' in spell %d", power->PowerType, Id); + continue; } + } - if (power->PowerType != POWER_HEALTH) - { - // Flat mod from caster auras by spell school and power type - Unit::AuraEffectList const& auras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL); - for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i) - { - if (!((*i)->GetMiscValue() & schoolMask)) - continue; + if (power->PowerCostMaxPct) + healthCost += int32(CalculatePct(caster->GetMaxHealth(), power->PowerCostMaxPct)); - if (!((*i)->GetMiscValueB() & (1 << power->PowerType))) - continue; + int32 optionalCost = int32(power->OptionalCost); + optionalCost += caster->GetTotalAuraModifier(SPELL_AURA_MOD_ADDITIONAL_POWER_COST, [this, power](AuraEffect const* aurEff) -> bool + { + return aurEff->GetMiscValue() == power->PowerType + && aurEff->IsAffectingSpell(this); + }); - powerCost += (*i)->GetAmount(); - } - } + if (optionalCost) + { + int32 remainingPower = caster->GetPower(Powers(power->PowerType)) - powerCost; + powerCost += RoundToInterval<int32>(remainingPower, 0, optionalCost); + } - // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) - if (HasAttribute(SPELL_ATTR4_SPELL_VS_EXTEND_COST)) + if (power->PowerType != POWER_HEALTH) + { + // Flat mod from caster auras by spell school and power type + Unit::AuraEffectList const& auras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL); + for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i) { - uint32 speed = 0; - if (SpellShapeshiftFormEntry const* ss = sSpellShapeshiftFormStore.LookupEntry(caster->GetShapeshiftForm())) - speed = ss->CombatRoundTime; - else - { - WeaponAttackType slot = BASE_ATTACK; - if (HasAttribute(SPELL_ATTR3_REQ_OFFHAND)) - slot = OFF_ATTACK; + if (!((*i)->GetMiscValue() & schoolMask)) + continue; - speed = caster->GetBaseAttackTime(slot); - } + if (!((*i)->GetMiscValueB() & (1 << power->PowerType))) + continue; - powerCost += speed / 100; + powerCost += (*i)->GetAmount(); } + } - // Apply cost mod by spell - if (Player* modOwner = caster->GetSpellModOwner()) + // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) + if (HasAttribute(SPELL_ATTR4_SPELL_VS_EXTEND_COST)) + { + uint32 speed = 0; + if (SpellShapeshiftFormEntry const* ss = sSpellShapeshiftFormStore.LookupEntry(caster->GetShapeshiftForm())) + speed = ss->CombatRoundTime; + else { - if (power->OrderIndex == 0) - modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost, spell); - else if (power->OrderIndex == 1) - modOwner->ApplySpellMod(Id, SPELLMOD_SPELL_COST2, powerCost, spell); - } + WeaponAttackType slot = BASE_ATTACK; + if (HasAttribute(SPELL_ATTR3_REQ_OFFHAND)) + slot = OFF_ATTACK; - if (!caster->IsControlledByPlayer() && G3D::fuzzyEq(power->PowerCostPct, 0.0f) && SpellLevel) - { - if (HasAttribute(SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)) - { - GtNpcManaCostScalerEntry const* spellScaler = sNpcManaCostScalerGameTable.GetRow(SpellLevel); - GtNpcManaCostScalerEntry const* casterScaler = sNpcManaCostScalerGameTable.GetRow(caster->getLevel()); - if (spellScaler && casterScaler) - powerCost *= casterScaler->Scaler / spellScaler->Scaler; - } + speed = caster->GetBaseAttackTime(slot); } - // PCT mod from user auras by spell school and power type - Unit::AuraEffectList const& aurasPct = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT); - for (Unit::AuraEffectList::const_iterator i = aurasPct.begin(); i != aurasPct.end(); ++i) - { - if (!((*i)->GetMiscValue() & schoolMask)) - continue; + powerCost += speed / 100; + } - if (!((*i)->GetMiscValueB() & (1 << power->PowerType))) - continue; + // Apply cost mod by spell + if (Player* modOwner = caster->GetSpellModOwner()) + { + if (power->OrderIndex == 0) + modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost, spell); + else if (power->OrderIndex == 1) + modOwner->ApplySpellMod(Id, SPELLMOD_SPELL_COST2, powerCost, spell); + } - powerCost += CalculatePct(powerCost, (*i)->GetAmount()); + if (!caster->IsControlledByPlayer() && G3D::fuzzyEq(power->PowerCostPct, 0.0f) && SpellLevel) + { + if (HasAttribute(SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)) + { + GtNpcManaCostScalerEntry const* spellScaler = sNpcManaCostScalerGameTable.GetRow(SpellLevel); + GtNpcManaCostScalerEntry const* casterScaler = sNpcManaCostScalerGameTable.GetRow(caster->getLevel()); + if (spellScaler && casterScaler) + powerCost *= casterScaler->Scaler / spellScaler->Scaler; } + } - if (power->PowerType == POWER_HEALTH) - { - healthCost += powerCost; + // PCT mod from user auras by spell school and power type + Unit::AuraEffectList const& aurasPct = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT); + for (Unit::AuraEffectList::const_iterator i = aurasPct.begin(); i != aurasPct.end(); ++i) + { + if (!((*i)->GetMiscValue() & schoolMask)) continue; - } - bool found = false; - for (SpellPowerCost& cost : costs) - { - if (cost.Power == Powers(power->PowerType)) - { - cost.Amount += powerCost; - found = true; - } - } + if (!((*i)->GetMiscValueB() & (1 << power->PowerType))) + continue; - if (!found) + powerCost += CalculatePct(powerCost, (*i)->GetAmount()); + } + + if (power->PowerType == POWER_HEALTH) + { + healthCost += powerCost; + continue; + } + + bool found = false; + for (SpellPowerCost& cost : costs) + { + if (cost.Power == Powers(power->PowerType)) { - SpellPowerCost cost; - cost.Power = Powers(power->PowerType); - cost.Amount = powerCost; - costs.push_back(cost); + cost.Amount += powerCost; + found = true; } } - if (healthCost > 0) + if (!found) { SpellPowerCost cost; - cost.Power = POWER_HEALTH; - cost.Amount = healthCost; + cost.Power = Powers(power->PowerType); + cost.Amount = powerCost; costs.push_back(cost); } - }; + } - if (!_hasPowerDifficultyData) // optimization - use static data for 99.5% cases (4753 of 4772 in build 6.1.0.19702) - collector(PowerCosts); - else - collector(sDB2Manager.GetSpellPowers(Id, caster->GetMap()->GetDifficultyID())); + if (healthCost > 0) + { + SpellPowerCost cost; + cost.Power = POWER_HEALTH; + cost.Amount = healthCost; + costs.push_back(cost); + } return costs; } @@ -4191,7 +4111,7 @@ SpellInfo const* SpellInfo::GetAuraRankForLevel(uint8 level) const return this; bool needRankSelection = false; - for (SpellEffectInfo const* effect : GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : _effects) { if (effect && IsPositiveEffect(effect->Effect) && (effect->Effect == SPELL_EFFECT_APPLY_AURA || @@ -4245,36 +4165,11 @@ bool SpellInfo::IsHighRankOf(SpellInfo const* spellInfo) const uint32 SpellInfo::GetSpellXSpellVisualId(Unit const* caster /*= nullptr*/) const { - if (caster) + for (SpellXSpellVisualEntry const* visual : _visuals) { - Difficulty difficulty = caster->GetMap()->GetDifficultyID(); - DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty); - while (difficultyEntry) - { - auto itr = _visuals.find(difficulty); - if (itr != _visuals.end()) - { - for (SpellXSpellVisualEntry const* visual : itr->second) - { - PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(visual->CasterPlayerConditionID); - if (!playerCondition || (caster->GetTypeId() == TYPEID_PLAYER && sConditionMgr->IsPlayerMeetingCondition(caster->ToPlayer(), playerCondition))) - return visual->ID; - } - } - - difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID); - } - } - - auto itr = _visuals.find(DIFFICULTY_NONE); - if (itr != _visuals.end()) - { - for (SpellXSpellVisualEntry const* visual : itr->second) - { - PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(visual->CasterPlayerConditionID); - if (!playerCondition || (caster && caster->GetTypeId() == TYPEID_PLAYER && sConditionMgr->IsPlayerMeetingCondition(caster->ToPlayer(), playerCondition))) - return visual->ID; - } + PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(visual->CasterPlayerConditionID); + if (!playerCondition || (caster && caster->GetTypeId() == TYPEID_PLAYER && sConditionMgr->IsPlayerMeetingCondition(caster->ToPlayer(), playerCondition))) + return visual->ID; } return 0; @@ -4299,29 +4194,26 @@ void SpellInfo::_InitializeExplicitTargetMask() bool dstSet = false; uint32 targetMask = Targets; // prepare target mask using effect target entries - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + for (SpellEffectInfo const* effect : _effects) { - for (SpellEffectInfo const* effect : itr->second) - { - if (!effect || !effect->IsEffect()) - continue; + if (!effect || !effect->IsEffect()) + continue; - targetMask |= effect->TargetA.GetExplicitTargetMask(srcSet, dstSet); - targetMask |= effect->TargetB.GetExplicitTargetMask(srcSet, dstSet); + targetMask |= effect->TargetA.GetExplicitTargetMask(srcSet, dstSet); + targetMask |= effect->TargetB.GetExplicitTargetMask(srcSet, dstSet); - // add explicit target flags based on spell effects which have EFFECT_IMPLICIT_TARGET_EXPLICIT and no valid target provided - if (effect->GetImplicitTargetType() != EFFECT_IMPLICIT_TARGET_EXPLICIT) - continue; + // add explicit target flags based on spell effects which have EFFECT_IMPLICIT_TARGET_EXPLICIT and no valid target provided + if (effect->GetImplicitTargetType() != EFFECT_IMPLICIT_TARGET_EXPLICIT) + continue; - // extend explicit target mask only if valid targets for effect could not be provided by target types - uint32 effectTargetMask = effect->GetMissingTargetMask(srcSet, dstSet, targetMask); + // extend explicit target mask only if valid targets for effect could not be provided by target types + uint32 effectTargetMask = effect->GetMissingTargetMask(srcSet, dstSet, targetMask); - // don't add explicit object/dest flags when spell has no max range - if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f) - effectTargetMask &= ~(TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_DEST_LOCATION); + // don't add explicit object/dest flags when spell has no max range + if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f) + effectTargetMask &= ~(TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_DEST_LOCATION); - targetMask |= effectTargetMask; - } + targetMask |= effectTargetMask; } ExplicitTargetMask = targetMask; @@ -4393,32 +4285,22 @@ bool SpellInfo::_IsPositiveEffect(uint32 effIndex, bool deep) const } // Special case: effects which determine positivity of whole spell - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) - { - for (SpellEffectInfo const* effect : itr->second) - { - if (effect && effect->IsAura() && effect->ApplyAuraName == SPELL_AURA_MOD_STEALTH) - return true; - } - } + for (SpellEffectInfo const* effect : _effects) + if (effect && effect->IsAura() && effect->ApplyAuraName == SPELL_AURA_MOD_STEALTH) + return true; - for (SpellEffectInfoMap::const_iterator itr = _effects.begin(); itr != _effects.end(); ++itr) + if (SpellEffectInfo const* effect = GetEffect(effIndex)) { - for (SpellEffectInfo const* effect : itr->second) + switch (effect->Effect) { - if (!effect || effect->EffectIndex != effIndex) - continue; - - switch (effect->Effect) - { case SPELL_EFFECT_DUMMY: // some explicitly required dummy effect sets switch (Id) { - case 28441: - return false; // AB Effect 000 - default: - break; + case 28441: + return false; // AB Effect 000 + default: + break; } break; // always positive effects (check before target checks that provided non-positive result in some case for positive effects) @@ -4463,20 +4345,17 @@ bool SpellInfo::_IsPositiveEffect(uint32 effIndex, bool deep) const case SPELL_AURA_PERIODIC_TRIGGER_SPELL: if (!deep) { - if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(effect->TriggerSpell)) + if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(effect->TriggerSpell, Difficulty)) { // negative targets of main spell return early - for (SpellEffectInfoMap::const_iterator it = spellTriggeredProto->_effects.begin(); it != spellTriggeredProto->_effects.end(); ++it) + for (SpellEffectInfo const* eff : spellTriggeredProto->_effects) { - for (SpellEffectInfo const* eff : itr->second) - { - if (!eff || !eff->Effect) - continue; - // if non-positive trigger cast targeted to positive target this main cast is non-positive - // this will place this spell auras as debuffs - if (_IsPositiveTarget(eff->TargetA.GetTarget(), eff->TargetB.GetTarget()) && !spellTriggeredProto->_IsPositiveEffect(eff->EffectIndex, true)) - return false; - } + if (!eff || !eff->Effect) + continue; + // if non-positive trigger cast targeted to positive target this main cast is non-positive + // this will place this spell auras as debuffs + if (_IsPositiveTarget(eff->TargetA.GetTarget(), eff->TargetB.GetTarget()) && !spellTriggeredProto->_IsPositiveEffect(eff->EffectIndex, true)) + return false; } } } @@ -4486,15 +4365,12 @@ bool SpellInfo::_IsPositiveEffect(uint32 effIndex, bool deep) const case SPELL_AURA_MOD_STUN: //have positive and negative spells, we can't sort its correctly at this moment. { bool more = false; - for (SpellEffectInfoMap::const_iterator i = _effects.begin(); i != _effects.end(); ++i) + for (SpellEffectInfo const* eff : _effects) { - for (SpellEffectInfo const* eff : i->second) + if (eff && eff->EffectIndex != 0) { - if (eff && eff->EffectIndex != 0) - { - more = true; - break; - } + more = true; + break; } } if (effIndex == 0 && !more) @@ -4581,21 +4457,21 @@ bool SpellInfo::_IsPositiveEffect(uint32 effIndex, bool deep) const } default: break; - } + } - // non-positive targets - if (!_IsPositiveTarget(effect->TargetA.GetTarget(), effect->TargetB.GetTarget())) - return false; + // non-positive targets + if (!_IsPositiveTarget(effect->TargetA.GetTarget(), effect->TargetB.GetTarget())) + return false; - // negative spell if triggered spell is negative - if (!deep && !effect->ApplyAuraName && effect->TriggerSpell) - { - if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(effect->TriggerSpell)) + // negative spell if triggered spell is negative + if (!deep && !effect->ApplyAuraName && effect->TriggerSpell) + { + if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(effect->TriggerSpell, Difficulty)) if (!spellTriggeredProto->_IsPositiveSpell()) return false; - } } } + // ok, positive return true; } @@ -4635,93 +4511,20 @@ bool SpellInfo::_IsPositiveTarget(uint32 targetA, uint32 targetB) void SpellInfo::_UnloadImplicitTargetConditionLists() { // find the same instances of ConditionList and delete them. - for (auto itr = _effects.begin(); itr != _effects.end(); ++itr) + for (uint32 i = 0; i < _effects.size(); ++i) { - for (uint32 i = 0; i < itr->second.size(); ++i) + if (SpellEffectInfo const* effect = _effects[i]) { - if (SpellEffectInfo const* effect = itr->second[i]) - { - ConditionContainer* cur = effect->ImplicitTargetConditions; - if (!cur) - continue; - for (uint8 j = i; j < itr->second.size(); ++j) - { - if (SpellEffectInfo const* eff = itr->second[j]) - { - if (eff->ImplicitTargetConditions == cur) - const_cast<SpellEffectInfo*>(eff)->ImplicitTargetConditions = NULL; - } - } - delete cur; - } - } - } -} - -SpellEffectInfoVector SpellInfo::GetEffectsForDifficulty(uint32 difficulty) const -{ - SpellEffectInfoVector effList; - - // downscale difficulty if original was not found - DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty); - while (difficultyEntry) - { - SpellEffectInfoMap::const_iterator effectItr = _effects.find(difficulty); - if (effectItr != _effects.end()) - { - for (SpellEffectInfo const* effect : effectItr->second) - { - if (effect) - { - if (effect->EffectIndex >= effList.size()) - effList.resize(effect->EffectIndex + 1); - - if (!effList[effect->EffectIndex]) - effList[effect->EffectIndex] = effect; - } - } - } + ConditionContainer* cur = effect->ImplicitTargetConditions; + if (!cur) + continue; - difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID); - } + for (uint8 j = i; j < _effects.size(); ++j) + if (SpellEffectInfo const* eff = _effects[j]) + if (eff->ImplicitTargetConditions == cur) + const_cast<SpellEffectInfo*>(eff)->ImplicitTargetConditions = nullptr; - // DIFFICULTY_NONE effects are the default effects, always active if current difficulty's effects don't overwrite - SpellEffectInfoMap::const_iterator itr = _effects.find(DIFFICULTY_NONE); - if (itr != _effects.end()) - { - for (SpellEffectInfo const* effect : itr->second) - { - if (effect) - { - if (effect->EffectIndex >= effList.size()) - effList.resize(effect->EffectIndex + 1); - - if (!effList[effect->EffectIndex]) - effList[effect->EffectIndex] = effect; - } + delete cur; } } - - return effList; -} - -SpellEffectInfo const* SpellInfo::GetEffect(uint32 difficulty, uint32 index) const -{ - DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty); - while (difficultyEntry) - { - SpellEffectInfoMap::const_iterator itr = _effects.find(difficulty); - if (itr != _effects.end()) - if (itr->second.size() > index && itr->second[index]) - return itr->second[index]; - - difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID); - } - - SpellEffectInfoMap::const_iterator itr = _effects.find(DIFFICULTY_NONE); - if (itr != _effects.end()) - if (itr->second.size() > index) - return itr->second[index]; - - return nullptr; } diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index e4b8709308b..4af84e40376 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -365,7 +365,7 @@ public: RealPointsPerLevel(0), BasePoints(0), PointsPerResource(0), Amplitude(0), ChainAmplitude(0), BonusCoefficient(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), PositionFacing(0), RadiusEntry(NULL), ChainTargets(0), ItemType(0), TriggerSpell(0), BonusCoefficientFromAP(0.0f), ImplicitTargetConditions(NULL) { } - SpellEffectInfo(SpellInfo const* spellInfo, uint8 effIndex, SpellEffectEntry const* effect); + SpellEffectInfo(SpellInfo const* spellInfo, SpellEffectEntry const* effect); bool IsEffect() const; bool IsEffect(SpellEffectName effectName) const; @@ -410,10 +410,6 @@ private: }; typedef std::vector<SpellEffectInfo const*> SpellEffectInfoVector; -typedef std::unordered_map<uint32, SpellEffectInfoVector> SpellEffectInfoMap; - -typedef std::vector<SpellEffectEntry const*> SpellEffectEntryVector; -typedef std::unordered_map<uint32, SpellEffectEntryVector> SpellEffectEntryMap; typedef std::vector<SpellXSpellVisualEntry const*> SpellVisualVector; typedef std::unordered_map<uint32, SpellVisualVector> SpellVisualMap; @@ -442,6 +438,7 @@ class TC_GAME_API SpellInfo public: uint32 Id; + ::Difficulty Difficulty; uint32 CategoryId; uint32 Dispel; uint32 Mechanic; @@ -492,7 +489,7 @@ class TC_GAME_API SpellInfo uint32 BaseLevel; uint32 SpellLevel; SpellDurationEntry const* DurationEntry; - std::vector<SpellPowerEntry const*> PowerCosts; + std::array<SpellPowerEntry const*, MAX_POWERS_PER_SPELL> PowerCosts; uint32 RangeIndex; SpellRangeEntry const* RangeEntry; float Speed; @@ -533,18 +530,15 @@ class TC_GAME_API SpellInfo uint32 ExplicitTargetMask; SpellChainNode const* ChainEntry; - SpellInfo(SpellInfoLoadHelper const& data, SpellEffectEntryMap const& effectsMap, SpellVisualMap&& visuals); + SpellInfo(SpellNameEntry const* spellName, ::Difficulty difficulty, SpellInfoLoadHelper const& data, SpellVisualVector&& visuals); ~SpellInfo(); uint32 GetCategory() const; - bool HasEffect(uint32 difficulty, SpellEffectName effect) const; bool HasEffect(SpellEffectName effect) const; - bool HasAura(uint32 difficulty, AuraType aura) const; - bool HasAreaAuraEffect(uint32 difficulty) const; + bool HasAura(AuraType aura) const; bool HasAreaAuraEffect() const; bool HasOnlyDamageEffects() const; bool HasTargetType(::Targets target) const; - bool HasTargetType(uint32 difficulty, ::Targets target) const; bool HasAttribute(SpellAttr0 attribute) const { return !!(Attributes & attribute); } bool HasAttribute(SpellAttr1 attribute) const { return !!(AttributesEx & attribute); } @@ -571,20 +565,20 @@ class TC_GAME_API SpellInfo bool IsExplicitDiscovery() const; bool IsLootCrafting() const; bool IsQuestTame() const; - bool IsProfession(uint32 difficulty = DIFFICULTY_NONE) const; - bool IsPrimaryProfession(uint32 difficulty = DIFFICULTY_NONE) const; - bool IsPrimaryProfessionFirstRank(uint32 difficulty = DIFFICULTY_NONE) const; + bool IsProfession() const; + bool IsPrimaryProfession() const; + bool IsPrimaryProfessionFirstRank() const; bool IsAbilityOfSkillType(uint32 skillType) const; - bool IsAffectingArea(uint32 difficulty) const; - bool IsTargetingArea(uint32 difficulty) const; + bool IsAffectingArea() const; + bool IsTargetingArea() const; bool NeedsExplicitUnitTarget() const; - bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell, uint32 difficulty) const; + bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const; bool IsPassive() const; bool IsAutocastable() const; bool IsStackableWithRanks() const; - bool IsPassiveStackableWithRanks(uint32 difficulty) const; + bool IsPassiveStackableWithRanks() const; bool IsMultiSlotAura() const; bool IsStackableOnOneSlotWithDifferentCasters() const; bool IsCooldownStartedOnEvent() const; @@ -632,7 +626,7 @@ class TC_GAME_API SpellInfo uint32 GetAllEffectsMechanicMask() const; uint32 GetEffectMechanicMask(uint32 effIndex) const; uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const; - Mechanics GetEffectMechanic(uint32 effIndex, uint32 difficulty) const; + Mechanics GetEffectMechanic(uint32 effIndex) const; //bool HasAnyEffectMechanic() const; uint32 GetDispelMask() const; static uint32 GetDispelMask(DispelType type); @@ -648,7 +642,7 @@ class TC_GAME_API SpellInfo int32 GetDuration() const; int32 GetMaxDuration() const; - uint32 GetMaxTicks(uint32 difficulty) const; + uint32 GetMaxTicks() const; uint32 CalcCastTime(uint8 level = 0, Spell* spell = nullptr) const; uint32 GetRecoveryTime() const; @@ -671,9 +665,8 @@ class TC_GAME_API SpellInfo uint32 GetSpellXSpellVisualId(Unit const* caster = nullptr) const; uint32 GetSpellVisual(Unit const* caster = nullptr) const; - SpellEffectInfoVector GetEffectsForDifficulty(uint32 difficulty) const; - SpellEffectInfo const* GetEffect(uint32 difficulty, uint32 index) const; - SpellEffectInfo const* GetEffect(uint32 index) const { return GetEffect(DIFFICULTY_NONE, index); } + SpellEffectInfoVector const& GetEffects() const { return _effects; } + SpellEffectInfo const* GetEffect(uint32 index) const { return index < _effects.size() ? _effects[index] : nullptr; } // spell diminishing returns DiminishingGroup GetDiminishingReturnsGroupForSpell() const; @@ -704,9 +697,8 @@ class TC_GAME_API SpellInfo void _UnloadSpellEffects(); private: - SpellEffectInfoMap _effects; - SpellVisualMap _visuals; - bool _hasPowerDifficultyData; + SpellEffectInfoVector _effects; + SpellVisualVector _visuals; SpellSpecificType _spellSpecific; AuraStateType _auraState; 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); diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index c121f1ec8f1..4ff3bfc858c 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -21,12 +21,14 @@ // For static or at-server-startup loaded spell data #include "Define.h" +#include "DBCEnums.h" #include "Duration.h" #include "IteratorPair.h" #include "RaceMask.h" #include "SharedDefines.h" #include "Util.h" +#include <functional> #include <map> #include <set> #include <vector> @@ -45,16 +47,19 @@ struct SpellCastingRequirementsEntry; struct SpellCategoriesEntry; struct SpellClassOptionsEntry; struct SpellCooldownsEntry; +struct SpellEffectEntry; struct SpellEquippedItemsEntry; struct SpellInterruptsEntry; struct SpellLevelsEntry; struct SpellMiscEntry; struct SpellNameEntry; +struct SpellPowerEntry; struct SpellReagentsEntry; struct SpellScalingEntry; struct SpellShapeshiftEntry; struct SpellTargetRestrictionsEntry; struct SpellTotemsEntry; +struct SpellXSpellVisualEntry; // only used in code enum SpellCategories @@ -282,8 +287,6 @@ struct SpellProcEntry uint32 Charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite }; -typedef std::unordered_map<uint32, SpellProcEntry> SpellProcMap; - enum EnchantProcAttributes { ENCHANT_PROC_ATTR_WHITE_HIT = 0x0000001, // enchant shall only proc off white hits (not abilities) @@ -578,8 +581,6 @@ typedef std::map<int32, PetDefaultSpellsEntry> PetDefaultSpellsMap; typedef std::vector<uint32> SpellCustomAttribute; typedef std::vector<bool> EnchantCustomAttribute; -typedef std::vector<SpellInfo*> SpellInfoMap; - typedef std::map<int32, std::vector<int32> > SpellLinkedMap; bool IsPrimaryProfessionSkill(uint32 skill); @@ -602,23 +603,24 @@ TC_GAME_API extern PetFamilySpellsStore sPetFamilySpells struct SpellInfoLoadHelper { - SpellNameEntry const* Entry = nullptr; - SpellAuraOptionsEntry const* AuraOptions = nullptr; SpellAuraRestrictionsEntry const* AuraRestrictions = nullptr; SpellCastingRequirementsEntry const* CastingRequirements = nullptr; SpellCategoriesEntry const* Categories = nullptr; SpellClassOptionsEntry const* ClassOptions = nullptr; SpellCooldownsEntry const* Cooldowns = nullptr; + std::array<SpellEffectEntry const*, MAX_SPELL_EFFECTS> Effects = { }; SpellEquippedItemsEntry const* EquippedItems = nullptr; SpellInterruptsEntry const* Interrupts = nullptr; SpellLevelsEntry const* Levels = nullptr; SpellMiscEntry const* Misc = nullptr; + std::array<SpellPowerEntry const*, MAX_POWERS_PER_SPELL> Powers; SpellReagentsEntry const* Reagents = nullptr; SpellScalingEntry const* Scaling = nullptr; SpellShapeshiftEntry const* Shapeshift = nullptr; SpellTargetRestrictionsEntry const* TargetRestrictions = nullptr; SpellTotemsEntry const* Totems = nullptr; + std::vector<SpellXSpellVisualEntry const*> Visuals; // only to group visuals when parsing sSpellXSpellVisualStore, not for loading }; typedef std::map<std::pair<uint32 /*SpellId*/, uint8 /*RaceId*/>, uint32 /*DisplayId*/> SpellTotemModelMap; @@ -675,7 +677,7 @@ class TC_GAME_API SpellMgr SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const; // Spell proc table - SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const; + SpellProcEntry const* GetSpellProcEntry(SpellInfo const* spellInfo) const; static bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo); // Spell threat table @@ -702,16 +704,18 @@ class TC_GAME_API SpellMgr SpellAreaForQuestAreaMapBounds GetSpellAreaForQuestAreaMapBounds(uint32 area_id, uint32 quest_id) const; // SpellInfo object management - SpellInfo const* GetSpellInfo(uint32 spellId) const { return spellId < GetSpellInfoStoreSize() ? mSpellInfoMap[spellId] : NULL; } + SpellInfo const* GetSpellInfo(uint32 spellId, Difficulty difficulty) const; + // Use this only with 100% valid spellIds - SpellInfo const* AssertSpellInfo(uint32 spellId) const + SpellInfo const* AssertSpellInfo(uint32 spellId, Difficulty difficulty) const { - ASSERT(spellId < GetSpellInfoStoreSize()); - SpellInfo const* spellInfo = mSpellInfoMap[spellId]; + SpellInfo const* spellInfo = GetSpellInfo(spellId, difficulty); ASSERT(spellInfo); return spellInfo; } - uint32 GetSpellInfoStoreSize() const { return uint32(mSpellInfoMap.size()); } + + void ForEachSpellInfo(std::function<void(SpellInfo const*)> callback); + void ForEachSpellInfoDifficulty(uint32 spellId, std::function<void(SpellInfo const*)> callback); void LoadPetFamilySpellsStore(); @@ -719,9 +723,6 @@ class TC_GAME_API SpellMgr BattlePetSpeciesEntry const* GetBattlePetSpecies(uint32 spellId) const; - private: - SpellInfo* _GetSpellInfo(uint32 spellId) { return spellId < GetSpellInfoStoreSize() ? mSpellInfoMap[spellId] : NULL; } - // Modifiers public: @@ -766,7 +767,6 @@ class TC_GAME_API SpellMgr SpellGroupSpellMap mSpellGroupSpell; SpellGroupStackMap mSpellGroupStack; SameEffectStackMap mSpellSameEffectStack; - SpellProcMap mSpellProcMap; SpellThreatMap mSpellThreatMap; SpellPetAuraMap mSpellPetAuraMap; SpellLinkedMap mSpellLinkedMap; @@ -781,7 +781,6 @@ class TC_GAME_API SpellMgr SkillLineAbilityMap mSkillLineAbilityMap; PetLevelupSpellMap mPetLevelupSpellMap; PetDefaultSpellsMap mPetDefaultSpellsMap; // only spells not listed in related mPetLevelupSpellMap entry - SpellInfoMap mSpellInfoMap; SpellTotemModelMap mSpellTotemModel; std::unordered_map<uint32, BattlePetSpeciesEntry const*> mBattlePets; }; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index e2a54597b2e..10722473019 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -39,7 +39,7 @@ bool _SpellScript::_ValidateSpellInfo(uint32 const* begin, uint32 const* end) bool allValid = true; while (begin != end) { - if (!sSpellMgr->GetSpellInfo(*begin)) + if (!sSpellMgr->GetSpellInfo(*begin, DIFFICULTY_NONE)) { TC_LOG_ERROR("scripts.spells", "_SpellScript::ValidateSpellInfo: Spell %u does not exist.", *begin); allValid = false; @@ -685,6 +685,11 @@ void SpellScript::SetCustomCastResultMessage(SpellCustomErrors result) m_spell->m_customError = result; } +Difficulty SpellScript::GetCastDifficulty() const +{ + return m_spell->GetCastDifficulty(); +} + SpellValue const* SpellScript::GetSpellValue() const { return m_spell->m_spellValue; @@ -692,7 +697,7 @@ SpellValue const* SpellScript::GetSpellValue() const SpellEffectInfo const* SpellScript::GetEffectInfo(SpellEffIndex effIndex) const { - return m_spell->GetEffect(effIndex); + return GetSpellInfo()->GetEffect(effIndex); } bool AuraScript::_Validate(SpellInfo const* entry) @@ -1230,3 +1235,8 @@ AuraApplication const* AuraScript::GetTargetApplication() const { return m_auraApplication; } + +Difficulty AuraScript::GetCastDifficulty() const +{ + return GetAura()->GetCastDifficulty(); +} diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 5b57a7df5b6..40920ba6f20 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -47,6 +47,7 @@ class WorldObject; struct SpellDestination; struct SpellModifier; struct SpellValue; +enum Difficulty : uint8; enum class ItemContext : uint8; #define SPELL_EFFECT_ANY (uint16)-1 @@ -483,6 +484,9 @@ class TC_GAME_API SpellScript : public _SpellScript void FinishCast(SpellCastResult result, uint32* param1 = nullptr, uint32* param2 = nullptr); void SetCustomCastResultMessage(SpellCustomErrors result); + + // returns desired cast difficulty for triggered spells + Difficulty GetCastDifficulty() const; }; // AuraScript interface - enum used for runtime checks of script function calls @@ -936,6 +940,9 @@ class TC_GAME_API AuraScript : public _SpellScript Unit* GetTarget() const; // returns AuraApplication object of currently processed target AuraApplication const* GetTargetApplication() const; + + // returns desired cast difficulty for triggered spells + Difficulty GetCastDifficulty() const; }; // diff --git a/src/server/game/Tools/CharacterDatabaseCleaner.cpp b/src/server/game/Tools/CharacterDatabaseCleaner.cpp index 0f384a9b2d7..86210d8f56e 100644 --- a/src/server/game/Tools/CharacterDatabaseCleaner.cpp +++ b/src/server/game/Tools/CharacterDatabaseCleaner.cpp @@ -130,7 +130,7 @@ void CharacterDatabaseCleaner::CleanCharacterSkills() bool CharacterDatabaseCleaner::SpellCheck(uint32 spell_id) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, DIFFICULTY_NONE); return spellInfo && !spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT); } diff --git a/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp b/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp index d14fa3065e1..510a110df47 100644 --- a/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp +++ b/src/server/scripts/Argus/AntorusTheBurningThrone/boss_garothi_worldbreaker.cpp @@ -604,13 +604,13 @@ class spell_garothi_fel_bombardment_periodic : public AuraScript bool Validate(SpellInfo const* spellInfo) override { - return ValidateSpellInfo({ uint32(spellInfo->GetEffect(DIFFICULTY_NONE, EFFECT_0)->BasePoints) }); + return ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0)->BasePoints) }); } void HandlePeriodic(AuraEffect const* /*aurEff*/) { if (Unit* caster = GetCaster()) - caster->CastSpell(GetTarget(), uint32(GetSpellInfo()->GetEffect(DIFFICULTY_NONE, EFFECT_0)->BasePoints), true); + caster->CastSpell(GetTarget(), uint32(GetSpellInfo()->GetEffect(EFFECT_0)->BasePoints), true); } void Register() override @@ -757,13 +757,13 @@ class spell_garothi_annihilation_selector : public SpellScript bool Validate(SpellInfo const* spellInfo) override { - return ValidateSpellInfo({ uint32(spellInfo->GetEffect(DIFFICULTY_NONE, EFFECT_0)->BasePoints) }); + return ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0)->BasePoints) }); } void HandleHit(SpellEffIndex effIndex) { if (Unit* caster = GetCaster()) - caster->CastSpell(GetHitUnit(), uint32(GetSpellInfo()->GetEffect(DIFFICULTY_NONE, effIndex)->BasePoints), true); + caster->CastSpell(GetHitUnit(), uint32(GetSpellInfo()->GetEffect(effIndex)->BasePoints), true); } void Register() override diff --git a/src/server/scripts/Commands/cs_cast.cpp b/src/server/scripts/Commands/cs_cast.cpp index b35374a0dac..9b783e28634 100644 --- a/src/server/scripts/Commands/cs_cast.cpp +++ b/src/server/scripts/Commands/cs_cast.cpp @@ -56,7 +56,7 @@ public: static bool CheckSpellExistsAndIsValid(ChatHandler* handler, uint32 spellId) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!spellInfo) { handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); diff --git a/src/server/scripts/Commands/cs_disable.cpp b/src/server/scripts/Commands/cs_disable.cpp index 212f1ba20c8..837d64af9c4 100644 --- a/src/server/scripts/Commands/cs_disable.cpp +++ b/src/server/scripts/Commands/cs_disable.cpp @@ -98,7 +98,7 @@ public: { case DISABLE_TYPE_SPELL: { - if (!sSpellMgr->GetSpellInfo(entry)) + if (!sSpellMgr->GetSpellInfo(entry, DIFFICULTY_NONE)) { handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index f0c6981f0f0..1de918cbc81 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -86,13 +86,13 @@ public: // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form uint32 spell = handler->extractSpellIdFromLink((char*)args); - if (!spell || !sSpellMgr->GetSpellInfo(spell)) + if (!spell || !sSpellMgr->GetSpellInfo(spell, DIFFICULTY_NONE)) return false; char const* all = strtok(NULL, " "); bool allRanks = all ? (strncmp(all, "all", strlen(all)) == 0) : false; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell, DIFFICULTY_NONE); if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer())) { handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spell); @@ -120,16 +120,13 @@ public: static bool HandleLearnAllGMCommand(ChatHandler* handler, char const* /*args*/) { - for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i) + for (std::pair<uint32 const, SkillLineAbilityEntry const*> skillSpell : Trinity::Containers::MakeIteratorPair(sSpellMgr->GetSkillLineAbilityMapBounds(SKILL_INTERNAL))) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(i); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillSpell.second->Spell, DIFFICULTY_NONE); if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer(), false)) continue; - if (!spellInfo->IsAbilityOfSkillType(SKILL_INTERNAL)) - continue; - - handler->GetSession()->GetPlayer()->LearnSpell(i, false); + handler->GetSession()->GetPlayer()->LearnSpell(skillSpell.second->Spell, false); } handler->SendSysMessage(LANG_LEARNING_GM_SKILLS); @@ -156,7 +153,7 @@ public: if (!entry) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(entry->Spell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(entry->Spell, DIFFICULTY_NONE); if (!spellInfo) continue; @@ -197,7 +194,7 @@ public: if (playerClass != talentInfo->ClassID) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE); if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer(), false)) continue; @@ -439,7 +436,7 @@ public: if (skillLine->ClassMask && (skillLine->ClassMask & classmask) == 0) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillLine->Spell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(skillLine->Spell, DIFFICULTY_NONE); if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, player, false)) continue; diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index e64c7161469..7db339d63c6 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -839,11 +839,10 @@ public: uint32 count = 0; uint32 maxResults = sWorld->getIntConfig(CONFIG_MAX_RESULTS_LOOKUP_COMMANDS); - // Search in Spell.dbc - for (uint32 id = 0; id < sSpellMgr->GetSpellInfoStoreSize(); id++) + // Search in SpellName.dbc + for (SpellNameEntry const* spellName : sSpellNameStore) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(id); - if (spellInfo) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellName->ID, DIFFICULTY_NONE)) { int locale = handler->GetSessionDbcLocale(); std::string name = spellInfo->SpellName->Str[locale]; @@ -875,16 +874,16 @@ public: return true; } - bool known = target && target->HasSpell(id); + bool known = target && target->HasSpell(spellInfo->Id); SpellEffectInfo const* effect = spellInfo->GetEffect(EFFECT_0); bool learn = effect ? (effect->Effect == SPELL_EFFECT_LEARN_SPELL) : false; - SpellInfo const* learnSpellInfo = effect ? sSpellMgr->GetSpellInfo(effect->TriggerSpell) : NULL; + SpellInfo const* learnSpellInfo = effect ? sSpellMgr->GetSpellInfo(effect->TriggerSpell, spellInfo->Difficulty) : NULL; bool talent = spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT); bool passive = spellInfo->IsPassive(); - bool active = target && target->HasAura(id); + bool active = target && target->HasAura(spellInfo->Id); // unit32 used to prevent interpreting uint8 as char at output // find rank of learned spell for learning spell, or talent rank @@ -893,9 +892,9 @@ public: // send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format std::ostringstream ss; if (handler->GetSession()) - ss << id << " - |cffffffff|Hspell:" << id << "|h[" << name; + ss << spellInfo->Id << " - |cffffffff|Hspell:" << spellInfo->Id << "|h[" << name; else - ss << id << " - " << name; + ss << spellInfo->Id << " - " << name; // include rank in link name if (rank) @@ -938,7 +937,7 @@ public: uint32 id = atoi((char*)args); - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(id)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(id, DIFFICULTY_NONE)) { int locale = handler->GetSessionDbcLocale(); std::string name = spellInfo->SpellName->Str[locale]; @@ -953,7 +952,7 @@ public: SpellEffectInfo const* effect = spellInfo->GetEffect(EFFECT_0); bool learn = effect? (effect->Effect == SPELL_EFFECT_LEARN_SPELL) : false; - SpellInfo const* learnSpellInfo = effect ? sSpellMgr->GetSpellInfo(effect->TriggerSpell) : NULL; + SpellInfo const* learnSpellInfo = effect ? sSpellMgr->GetSpellInfo(effect->TriggerSpell, DIFFICULTY_NONE) : NULL; bool talent = spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT); bool passive = spellInfo->IsPassive(); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 23804a75a21..d35904921eb 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -322,10 +322,10 @@ public: // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form uint32 spellId = handler->extractSpellIdFromLink((char*)args); - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, target->GetMap()->GetDifficultyID())) { ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, target->GetMapId(), spellId, target->GetMap()->GenerateLowGuid<HighGuid::Cast>()); - Aura::TryRefreshStackOrCreate(spellInfo, castId, MAX_EFFECT_MASK, target, target); + Aura::TryRefreshStackOrCreate(spellInfo, castId, MAX_EFFECT_MASK, target, target, target->GetMap()->GetDifficultyID()); } return true; @@ -795,7 +795,7 @@ public: if (!spellIid) return false; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellIid); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellIid, target->GetMap()->GetDifficultyID()); if (!spellInfo) { handler->PSendSysMessage(LANG_UNKNOWN_SPELL, owner == handler->GetSession()->GetPlayer() ? handler->GetTrinityString(LANG_YOU) : nameLink.c_str()); @@ -1017,7 +1017,7 @@ public: if (player->IsInFlight() || player->IsInCombat()) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_UNSTUCK_ID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_UNSTUCK_ID, DIFFICULTY_NONE); if (!spellInfo) return false; @@ -2426,11 +2426,11 @@ public: if (!spellid) return false; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid, attacker->GetMap()->GetDifficultyID()); if (!spellInfo) return false; - SpellNonMeleeDamage damageInfo(attacker, target, spellid, spellInfo->GetSpellXSpellVisualId(handler->GetSession()->GetPlayer()), spellInfo->SchoolMask); + SpellNonMeleeDamage damageInfo(attacker, target, spellInfo, spellInfo->GetSpellXSpellVisualId(handler->GetSession()->GetPlayer()), spellInfo->SchoolMask); damageInfo.damage = damage; attacker->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); target->DealSpellDamage(&damageInfo, true); diff --git a/src/server/scripts/Commands/cs_pet.cpp b/src/server/scripts/Commands/cs_pet.cpp index 1e0cd4ab835..124d67fb722 100644 --- a/src/server/scripts/Commands/cs_pet.cpp +++ b/src/server/scripts/Commands/cs_pet.cpp @@ -148,7 +148,7 @@ public: uint32 spellId = handler->extractSpellIdFromLink((char*)args); - if (!spellId || !sSpellMgr->GetSpellInfo(spellId)) + if (!spellId || !sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE)) return false; // Check if pet already has it @@ -160,7 +160,7 @@ public: } // Check if spell is valid - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo)) { handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spellId); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp index 1c4f1c112eb..b1c88b9c6d2 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp @@ -311,7 +311,7 @@ public: void EnfeebleHealthEffect() { - SpellInfo const* info = sSpellMgr->GetSpellInfo(SPELL_ENFEEBLE_EFFECT); + SpellInfo const* info = sSpellMgr->GetSpellInfo(SPELL_ENFEEBLE_EFFECT, GetDifficulty()); if (!info) return; diff --git a/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp index f297095ff31..0dfe70efd5f 100644 --- a/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp +++ b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp @@ -819,7 +819,7 @@ class spell_baleroc_vital_flame : public AuraScript } stacks = GetCaster()->GetAuraCount(SPELL_VITAL_SPARK); - int32 healingPct = sSpellMgr->AssertSpellInfo(SPELL_VITAL_SPARK)->GetEffect(EFFECT_0)->BasePoints * stacks; + int32 healingPct = sSpellMgr->AssertSpellInfo(SPELL_VITAL_SPARK, GetCastDifficulty())->GetEffect(EFFECT_0)->BasePoints * stacks; if (GetAura()->GetEffect(EFFECT_0)->GetAmount() < healingPct) GetAura()->GetEffect(EFFECT_0)->SetAmount(healingPct); diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp index b39f0f66507..eb129c37473 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp @@ -131,7 +131,7 @@ public: // phase the player target->CastSpell(target, SPELL_INSANITY_TARGET + insanityHandled, true); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_INSANITY_TARGET + insanityHandled); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_INSANITY_TARGET + insanityHandled, GetDifficulty()); if (!spellInfo) return; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp index 874e9c77235..7500fec1759 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp @@ -232,8 +232,8 @@ class spell_saviana_conflagration_init : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) override { - if (!sSpellMgr->GetSpellInfo(SPELL_FLAME_BEACON) - || !sSpellMgr->GetSpellInfo(SPELL_CONFLAGRATION_2)) + if (!sSpellMgr->GetSpellInfo(SPELL_FLAME_BEACON, DIFFICULTY_NONE) + || !sSpellMgr->GetSpellInfo(SPELL_CONFLAGRATION_2, DIFFICULTY_NONE)) return false; return true; } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp index 7b2575f8935..c5f5fb349de 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp @@ -815,7 +815,7 @@ class spell_blood_queen_pact_of_the_darkfallen_dmg : public SpellScriptLoader // this is an additional effect to be executed void PeriodicTick(AuraEffect const* aurEff) { - SpellInfo const* damageSpell = sSpellMgr->AssertSpellInfo(SPELL_PACT_OF_THE_DARKFALLEN_DAMAGE); + SpellInfo const* damageSpell = sSpellMgr->AssertSpellInfo(SPELL_PACT_OF_THE_DARKFALLEN_DAMAGE, GetCastDifficulty()); int32 damage = damageSpell->GetEffect(EFFECT_0)->CalcValue(); float multiplier = 0.3375f + 0.1f * uint32(aurEff->GetTickNumber() / 10); // do not convert to 0.01f - we need tick number/10 as INT (damage increases every 10 ticks) damage = int32(damage * multiplier); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp index d40e5b8beb8..2ab13c49d28 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -1845,7 +1845,7 @@ class spell_igb_rocket_pack : public SpellScriptLoader void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - SpellInfo const* damageInfo = sSpellMgr->AssertSpellInfo(SPELL_ROCKET_PACK_DAMAGE); + SpellInfo const* damageInfo = sSpellMgr->AssertSpellInfo(SPELL_ROCKET_PACK_DAMAGE, GetCastDifficulty()); GetTarget()->CastCustomSpell(SPELL_ROCKET_PACK_DAMAGE, SPELLVALUE_BASE_POINT0, 2 * (damageInfo->GetEffect(EFFECT_0)->CalcValue() + aurEff->GetTickNumber() * aurEff->GetPeriod()), NULL, TRIGGERED_FULL_MASK); GetTarget()->CastSpell(nullptr, SPELL_ROCKET_BURST, TRIGGERED_FULL_MASK); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 11b5ad24e9a..7f69a62017d 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -589,7 +589,7 @@ class spell_marrowgar_coldflame_damage : public SpellScriptLoader if (target->HasAura(SPELL_IMPALED)) return false; - if (SpellEffectInfo const* effect = GetSpellInfo()->GetEffect(target->GetMap()->GetDifficultyID(), EFFECT_0)) + if (SpellEffectInfo const* effect = GetSpellInfo()->GetEffect(EFFECT_0)) if (target->GetExactDist2d(GetOwner()) > effect->CalcRadius()) return false; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 116843c2398..e277bb150a1 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -401,14 +401,14 @@ class boss_professor_putricide : public CreatureScript { case PHASE_COMBAT_2: { - SpellInfo const* spell = sSpellMgr->GetSpellInfo(SPELL_CREATE_CONCOCTION); + SpellInfo const* spell = sSpellMgr->GetSpellInfo(SPELL_CREATE_CONCOCTION, GetDifficulty()); DoCast(me, SPELL_CREATE_CONCOCTION); events.ScheduleEvent(EVENT_PHASE_TRANSITION, spell->CalcCastTime() + 100); break; } case PHASE_COMBAT_3: { - SpellInfo const* spell = sSpellMgr->GetSpellInfo(SPELL_GUZZLE_POTIONS); + SpellInfo const* spell = sSpellMgr->GetSpellInfo(SPELL_GUZZLE_POTIONS, GetDifficulty()); DoCast(me, SPELL_GUZZLE_POTIONS); events.ScheduleEvent(EVENT_PHASE_TRANSITION, spell->CalcCastTime() + 100); break; @@ -1154,7 +1154,7 @@ class spell_putricide_choking_gas_bomb : public SpellScriptLoader void HandleScript(SpellEffIndex /*effIndex*/) { uint32 skipIndex = urand(0, 2); - for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffectsForDifficulty(GetCaster()->GetMap()->GetDifficultyID())) + for (SpellEffectInfo const* effect : GetSpellInfo()->GetEffects()) { if (!effect || effect->EffectIndex == skipIndex) continue; @@ -1317,7 +1317,7 @@ class spell_putricide_mutated_plague : public SpellScriptLoader return; uint32 triggerSpell = GetSpellInfo()->GetEffect(aurEff->GetEffIndex())->TriggerSpell; - SpellInfo const* spell = sSpellMgr->AssertSpellInfo(triggerSpell); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(triggerSpell, GetCastDifficulty()); int32 damage = spell->GetEffect(EFFECT_0)->CalcValue(caster); float multiplier = 2.0f; @@ -1333,7 +1333,7 @@ class spell_putricide_mutated_plague : public SpellScriptLoader void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { uint32 healSpell = uint32(GetSpellInfo()->GetEffect(EFFECT_0)->CalcValue()); - SpellInfo const* healSpellInfo = sSpellMgr->GetSpellInfo(healSpell); + SpellInfo const* healSpellInfo = sSpellMgr->GetSpellInfo(healSpell, GetCastDifficulty()); if (!healSpellInfo) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp index d0fdf6557c1..f8d8fcea526 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp @@ -552,7 +552,7 @@ class spell_rotface_mutated_infection : public SpellScriptLoader void HandleEffectRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { Unit* target = GetTarget(); - target->CastSpell(target, uint32(GetAura()->GetSpellEffectInfo(EFFECT_2)->CalcValue()), true, nullptr, aurEff, GetCasterGUID()); + target->CastSpell(target, uint32(GetSpellInfo()->GetEffect(EFFECT_2)->CalcValue()), true, nullptr, aurEff, GetCasterGUID()); } void Register() override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index e1cc3c12f54..6f9f082ef8c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -1124,7 +1124,7 @@ class spell_sindragosa_s_fury : public SpellScriptLoader uint32 damage = (uint32(GetEffectValue() / _targetCount) * randomResist) / 10; - SpellNonMeleeDamage damageInfo(GetCaster(), GetHitUnit(), GetSpellInfo()->Id, GetSpell()->m_SpellVisual, GetSpellInfo()->SchoolMask); + SpellNonMeleeDamage damageInfo(GetCaster(), GetHitUnit(), GetSpellInfo(), GetSpell()->m_SpellVisual, GetSpellInfo()->SchoolMask); damageInfo.damage = damage; GetCaster()->DealSpellDamage(&damageInfo, false); GetCaster()->SendSpellNonMeleeDamageLog(&damageInfo); @@ -1564,7 +1564,7 @@ class spell_frostwarden_handler_focus_fire : public SpellScriptLoader PreventDefaultAction(); if (Unit* caster = GetCaster()) { - if (SpellEffectInfo const* effect = GetSpellInfo()->GetEffect(caster->GetMap()->GetDifficultyID(), EFFECT_1)) + if (SpellEffectInfo const* effect = GetSpellInfo()->GetEffect(EFFECT_1)) caster->AddThreat(GetTarget(), -float(effect->CalcValue())); caster->GetAI()->SetData(DATA_WHELP_MARKER, 0); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp index b4616c9629f..67e665862ff 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp @@ -57,7 +57,7 @@ class icecrown_citadel_teleport : public GameObjectScript ClearGossipMenuFor(player); CloseGossipMenuFor(player); - SpellInfo const* spell = sSpellMgr->GetSpellInfo(TeleportSpells[gossipListId]); + SpellInfo const* spell = sSpellMgr->GetSpellInfo(TeleportSpells[gossipListId], DIFFICULTY_NONE); if (!spell) return false; @@ -88,7 +88,7 @@ class at_frozen_throne_teleport : public AreaTriggerScript { if (player->IsInCombat()) { - if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(FROZEN_THRONE_TELEPORT)) + if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(FROZEN_THRONE_TELEPORT, DIFFICULTY_NONE)) { ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, player->GetMapId(), spell->Id, player->GetMap()->GenerateLowGuid<HighGuid::Cast>()); Spell::SendCastResult(player, spell, 0, castId, SPELL_FAILED_AFFECTING_COMBAT); diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index 117c21d197a..8fbf23d4a44 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -1335,9 +1335,7 @@ public: bool Validate(SpellInfo const* spellInfo) override { - if (!sSpellMgr->GetSpellInfo(spellInfo->GetEffect(EFFECT_0)->CalcValue())) - return false; - return true; + return ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0)->CalcValue()) }); } void HandleScript(SpellEffIndex /*effIndex*/) @@ -1441,9 +1439,7 @@ public: bool Validate(SpellInfo const* /*spellInfo*/) override { - if (!sSpellMgr->GetSpellInfo(SPELL_FATAL_STRIKE_DAMAGE)) - return false; - return true; + return ValidateSpellInfo({ SPELL_FATAL_STRIKE_DAMAGE }); } void HandleDummy(SpellEffIndex /*effIndex*/) @@ -1520,9 +1516,7 @@ public: bool Validate(SpellInfo const* /*spellInfo*/) override { - if (!sSpellMgr->GetSpellInfo(SPELL_FIGHT_WYRM)) - return false; - return true; + return ValidateSpellInfo({ SPELL_FIGHT_WYRM }); } void HandleDummy(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index d0c189e7931..19f4018af10 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -330,7 +330,7 @@ class spell_dk_dancing_rune_weapon : public SpellScriptLoader return; int32 amount = static_cast<int32>(damageInfo->GetDamage()) / 2; - SpellNonMeleeDamage log(drw, drw->GetVictim(), spellInfo->Id, spellInfo->GetSpellXSpellVisualId(drw), spellInfo->GetSchoolMask()); + SpellNonMeleeDamage log(drw, drw->GetVictim(), spellInfo, spellInfo->GetSpellXSpellVisualId(drw), spellInfo->GetSchoolMask()); log.damage = amount; drw->DealDamage(drw->GetVictim(), amount, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true); drw->SendSpellNonMeleeDamageLog(&log); diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 9dc071b08a2..48d63353a34 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -994,7 +994,7 @@ public: if (player->GetSkillValue(SKILL_RIDING) < 75) return SPELL_FAILED_APPRENTICE_RIDING_REQUIREMENT; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(player->IsInWater() ? SPELL_DRUID_FORM_AQUATIC : SPELL_DRUID_FORM_STAG); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(player->IsInWater() ? SPELL_DRUID_FORM_AQUATIC : SPELL_DRUID_FORM_STAG, GetCastDifficulty()); return spellInfo->CheckLocation(player->GetMapId(), player->GetZoneId(), player->GetAreaId(), player); } @@ -1053,7 +1053,7 @@ public: SpellCastResult CheckLocationForForm(uint32 spell) { Player* player = GetTarget()->ToPlayer(); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell, GetCastDifficulty()); return spellInfo->CheckLocation(player->GetMapId(), player->GetZoneId(), player->GetAreaId(), player); } }; @@ -1135,7 +1135,7 @@ public: SpellCastResult CheckLocationForForm(uint32 spell_id) { Player* player = GetTarget()->ToPlayer(); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, GetCastDifficulty()); if (!player->GetMap()->IsOutdoors(player->GetPhaseShift(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ())) return SPELL_FAILED_ONLY_OUTDOORS; @@ -1244,9 +1244,9 @@ class spell_dru_t10_balance_4p_bonus : public SpellScriptLoader Unit* caster = eventInfo.GetActor(); Unit* target = eventInfo.GetProcTarget(); - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DRUID_LANGUISH); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DRUID_LANGUISH, GetCastDifficulty()); int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); - amount /= spellInfo->GetMaxTicks(DIFFICULTY_NONE); + amount /= spellInfo->GetMaxTicks(); // Add remaining ticks to damage done amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_DRUID_LANGUISH, SPELL_AURA_PERIODIC_DAMAGE); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 85fb71cccec..2824a5e637b 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1976,9 +1976,9 @@ class spell_gen_mounted_charge: public SpellScriptLoader void Register() override { - SpellInfo const* spell = sSpellMgr->AssertSpellInfo(m_scriptSpellId); + SpellInfo const* spell = sSpellMgr->AssertSpellInfo(m_scriptSpellId, DIFFICULTY_NONE); - if (spell->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_SCRIPT_EFFECT)) + if (spell->HasEffect(SPELL_EFFECT_SCRIPT_EFFECT)) OnEffectHitTarget += SpellEffectFn(spell_gen_mounted_charge_SpellScript::HandleScriptEffect, EFFECT_FIRST_FOUND, SPELL_EFFECT_SCRIPT_EFFECT); if (spell->GetEffect(EFFECT_0)->Effect == SPELL_EFFECT_CHARGE) diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index 54b75b7df89..f51d7730b8e 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -728,9 +728,9 @@ class spell_hun_readiness : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath - GetCaster()->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) + GetCaster()->GetSpellHistory()->ResetCooldowns([this](SpellHistory::CooldownStorageType::iterator itr) { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, GetCastDifficulty()); ///! If spellId in cooldown map isn't valid, the above will return a null pointer. if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 7461e52e1b4..2c32c6fd220 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -161,9 +161,9 @@ class spell_item_alchemist_stone : public SpellScriptLoader uint32 spellId = 0; int32 amount = int32(eventInfo.GetDamageInfo()->GetDamage() * 0.4f); - if (eventInfo.GetDamageInfo()->GetSpellInfo()->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_HEAL)) + if (eventInfo.GetDamageInfo()->GetSpellInfo()->HasEffect(SPELL_EFFECT_HEAL)) spellId = SPELL_ALCHEMIST_STONE_EXTRA_HEAL; - else if (eventInfo.GetDamageInfo()->GetSpellInfo()->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_ENERGIZE)) + else if (eventInfo.GetDamageInfo()->GetSpellInfo()->HasEffect(SPELL_EFFECT_ENERGIZE)) spellId = SPELL_ALCHEMIST_STONE_EXTRA_MANA; if (!spellId) @@ -517,7 +517,7 @@ class spell_item_deadly_precision_dummy : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DEADLY_PRECISION); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_DEADLY_PRECISION, GetCastDifficulty()); GetCaster()->CastCustomSpell(spellInfo->Id, SPELLVALUE_AURA_STACK, spellInfo->StackAmount, GetCaster(), true); } @@ -1100,7 +1100,7 @@ class spell_item_gnomish_death_ray : public SpellScriptLoader } }; -// Item 10721: Gnomish Harm Prevention Belt +// Item 10721: Gnomish Harm Prevention Belt // 13234 - Harm Prevention Belt enum HarmPreventionBelt { @@ -1118,9 +1118,7 @@ public: bool Validate(SpellInfo const* /*spellInfo*/) override { - if (!sSpellMgr->GetSpellInfo(SPELL_FORCEFIELD_COLLAPSE)) - return false; - return true; + return ValidateSpellInfo({ SPELL_FORCEFIELD_COLLAPSE }); } void HandleProc(ProcEventInfo& /*eventInfo*/) diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index 0a4e847eb14..ec0993b2939 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -167,7 +167,7 @@ class spell_mage_cauterize_AuraScript : public AuraScript } GetTarget()->SetHealth(GetTarget()->CountPctFromMaxHealth(effect1->GetAmount())); - GetTarget()->CastSpell(GetTarget(), GetAura()->GetSpellEffectInfo(EFFECT_2)->TriggerSpell, TRIGGERED_FULL_MASK); + GetTarget()->CastSpell(GetTarget(), GetSpellInfo()->GetEffect(EFFECT_2)->TriggerSpell, TRIGGERED_FULL_MASK); GetTarget()->CastSpell(GetTarget(), SPELL_MAGE_CAUTERIZE_DOT, TRIGGERED_FULL_MASK); GetTarget()->CastSpell(GetTarget(), SPELL_MAGE_CAUTERIZED, TRIGGERED_FULL_MASK); } @@ -326,10 +326,10 @@ class spell_mage_ignite : public AuraScript { PreventDefaultAction(); - SpellInfo const* igniteDot = sSpellMgr->AssertSpellInfo(SPELL_MAGE_IGNITE); + SpellInfo const* igniteDot = sSpellMgr->AssertSpellInfo(SPELL_MAGE_IGNITE, GetCastDifficulty()); int32 pct = aurEff->GetAmount(); - int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), pct) / igniteDot->GetMaxTicks(DIFFICULTY_NONE)); + int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), pct) / igniteDot->GetMaxTicks()); amount += eventInfo.GetProcTarget()->GetRemainingPeriodicAmount(eventInfo.GetActor()->GetGUID(), SPELL_MAGE_IGNITE, SPELL_AURA_PERIODIC_DAMAGE); GetTarget()->CastCustomSpell(SPELL_MAGE_IGNITE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, nullptr, aurEff); } @@ -518,7 +518,7 @@ class spell_mage_ring_of_frost : public AuraScript void Apply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { std::list<TempSummon*> minions; - GetTarget()->GetAllMinionsByEntry(minions, sSpellMgr->AssertSpellInfo(SPELL_MAGE_RING_OF_FROST_SUMMON)->GetEffect(EFFECT_0)->MiscValue); + GetTarget()->GetAllMinionsByEntry(minions, sSpellMgr->AssertSpellInfo(SPELL_MAGE_RING_OF_FROST_SUMMON, GetCastDifficulty())->GetEffect(EFFECT_0)->MiscValue); // Get the last summoned RoF, save it and despawn older ones for (TempSummon* summon : minions) @@ -568,7 +568,7 @@ class spell_mage_ring_of_frost_freeze : public SpellScript void FilterTargets(std::list<WorldObject*>& targets) { WorldLocation const* dest = GetExplTargetDest(); - float outRadius = sSpellMgr->AssertSpellInfo(SPELL_MAGE_RING_OF_FROST_SUMMON)->GetEffect(EFFECT_0)->CalcRadius(); + float outRadius = sSpellMgr->AssertSpellInfo(SPELL_MAGE_RING_OF_FROST_SUMMON, GetCastDifficulty())->GetEffect(EFFECT_0)->CalcRadius(); float inRadius = 6.5f; targets.remove_if([dest, outRadius, inRadius](WorldObject* target) diff --git a/src/server/scripts/Spells/spell_monk.cpp b/src/server/scripts/Spells/spell_monk.cpp index 534d57fb091..e501e20e7e3 100644 --- a/src/server/scripts/Spells/spell_monk.cpp +++ b/src/server/scripts/Spells/spell_monk.cpp @@ -132,7 +132,7 @@ class spell_monk_provoke : public SpellScript { if (GetExplTargetUnit()->GetEntry() != BlackOxStatusEntry) { - SpellInfo const* singleTarget = sSpellMgr->AssertSpellInfo(SPELL_MONK_PROVOKE_SINGLE_TARGET); + SpellInfo const* singleTarget = sSpellMgr->AssertSpellInfo(SPELL_MONK_PROVOKE_SINGLE_TARGET, GetCastDifficulty()); SpellCastResult singleTargetExplicitResult = singleTarget->CheckExplicitTarget(GetCaster(), GetExplTargetUnit()); if (singleTargetExplicitResult != SPELL_CAST_OK) return singleTargetExplicitResult; diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 9f37671c8f3..3d43d162418 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -765,7 +765,7 @@ class spell_pal_holy_shock : public SpellScriptLoader bool Validate(SpellInfo const* spellInfo) override { - SpellInfo const* firstRankSpellInfo = sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_SHOCK_R1); + SpellInfo const* firstRankSpellInfo = sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_SHOCK_R1, DIFFICULTY_NONE); if (!firstRankSpellInfo) return false; @@ -940,7 +940,7 @@ class spell_pal_judgement : public SpellScriptLoader { if ((*i)->GetSpellInfo()->GetSpellSpecific() == SPELL_SPECIFIC_SEAL && (*i)->GetEffIndex() == EFFECT_2) { - if (sSpellMgr->GetSpellInfo((*i)->GetAmount())) + if (sSpellMgr->GetSpellInfo((*i)->GetAmount(), GetCastDifficulty())) { spellId = (*i)->GetAmount(); break; @@ -1411,9 +1411,9 @@ class spell_pal_t8_2p_bonus : public SpellScriptLoader Unit* caster = eventInfo.GetActor(); Unit* target = eventInfo.GetProcTarget(); - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_HOLY_MENDING); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PALADIN_HOLY_MENDING, GetCastDifficulty()); int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); - amount /= spellInfo->GetMaxTicks(DIFFICULTY_NONE); + amount /= spellInfo->GetMaxTicks(); // Add remaining ticks to damage done amount += target->GetRemainingPeriodicAmount(caster->GetGUID(), SPELL_PALADIN_HOLY_MENDING, SPELL_AURA_PERIODIC_HEAL); diff --git a/src/server/scripts/Spells/spell_pet.cpp b/src/server/scripts/Spells/spell_pet.cpp index 7aaba87a2da..0ff0ebde0e5 100644 --- a/src/server/scripts/Spells/spell_pet.cpp +++ b/src/server/scripts/Spells/spell_pet.cpp @@ -897,7 +897,7 @@ public: if (itr != pet->ToPet()->m_spells.end()) // If pet has Wild Hunt { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, GetCastDifficulty()); // Then get the SpellProto and add the dummy effect value AddPct(mod, spellInfo->GetEffect(EFFECT_0)->CalcValue()); } @@ -939,7 +939,7 @@ public: if (itr != pet->ToPet()->m_spells.end()) // If pet has Wild Hunt { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, GetCastDifficulty()); // Then get the SpellProto and add the dummy effect value mod += CalculatePct(1.0f, spellInfo->GetEffect(EFFECT_1)->CalcValue()); } @@ -969,7 +969,7 @@ public: if (itr != pet->ToPet()->m_spells.end()) // If pet has Wild Hunt { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); // Then get the SpellProto and add the dummy effect value + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, GetCastDifficulty()); // Then get the SpellProto and add the dummy effect value mod += CalculatePct(1.0f, spellInfo->GetEffect(EFFECT_1)->CalcValue()); } diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index 7436742b425..34a09aa9150 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -541,8 +541,8 @@ class spell_pri_glyph_of_prayer_of_healing : public SpellScriptLoader if (!healInfo || !healInfo->GetHeal()) return; - SpellInfo const* triggeredSpellInfo = sSpellMgr->AssertSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL); - int32 heal = int32(CalculatePct(healInfo->GetHeal(), aurEff->GetAmount()) / triggeredSpellInfo->GetMaxTicks(DIFFICULTY_NONE)); + SpellInfo const* triggeredSpellInfo = sSpellMgr->AssertSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL, GetCastDifficulty()); + int32 heal = int32(CalculatePct(healInfo->GetHeal(), aurEff->GetAmount()) / triggeredSpellInfo->GetMaxTicks()); GetTarget()->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL, SPELLVALUE_BASE_POINT0, heal, eventInfo.GetProcTarget(), true, NULL, aurEff); } @@ -752,7 +752,7 @@ class spell_pri_leap_of_faith_effect_trigger : public SpellScriptLoader SpellCastTargets targets; targets.SetDst(destPos); targets.SetUnitTarget(GetCaster()); - GetHitUnit()->CastSpell(targets, sSpellMgr->GetSpellInfo(GetEffectValue()), NULL); + GetHitUnit()->CastSpell(targets, sSpellMgr->GetSpellInfo(GetEffectValue(), GetCastDifficulty()), NULL); } void Register() override @@ -963,7 +963,7 @@ class spell_pri_penance : public SpellScriptLoader bool Validate(SpellInfo const* spellInfo) override { - SpellInfo const* firstRankSpellInfo = sSpellMgr->GetSpellInfo(SPELL_PRIEST_PENANCE_R1); + SpellInfo const* firstRankSpellInfo = sSpellMgr->GetSpellInfo(SPELL_PRIEST_PENANCE_R1, DIFFICULTY_NONE); if (!firstRankSpellInfo) return false; @@ -1340,9 +1340,9 @@ class spell_pri_t10_heal_2p_bonus : public SpellScriptLoader if (!healInfo || !healInfo->GetHeal()) return; - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PRIEST_BLESSED_HEALING); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_PRIEST_BLESSED_HEALING, GetCastDifficulty()); int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); - amount /= spellInfo->GetMaxTicks(DIFFICULTY_NONE); + amount /= spellInfo->GetMaxTicks(); // Add remaining ticks to healing done Unit* caster = eventInfo.GetActor(); @@ -1523,7 +1523,7 @@ class spell_pri_angelic_feather_trigger : public SpellScriptLoader { SpellCastTargets targets; targets.SetDst(destPos); - GetCaster()->CastSpell(targets, sSpellMgr->GetSpellInfo(SPELL_PRIEST_ANGELIC_FEATHER_AREATRIGGER), nullptr); + GetCaster()->CastSpell(targets, sSpellMgr->GetSpellInfo(SPELL_PRIEST_ANGELIC_FEATHER_AREATRIGGER, GetCastDifficulty()), nullptr); } } diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index b53a9822eff..5f1121648f0 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -288,7 +288,7 @@ class spell_rog_deadly_poison : public SpellScriptLoader if (enchant->Effect[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(enchant->EffectArg[s]); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(enchant->EffectArg[s], DIFFICULTY_NONE); if (!spellInfo) { TC_LOG_ERROR("spells", "Player::CastItemCombatSpell Enchant %i, player (Name: %s, %s) cast unknown spell %i", enchant->ID, player->GetName().c_str(), player->GetGUID().ToString().c_str(), enchant->EffectArg[s]); @@ -486,9 +486,9 @@ class spell_rog_preparation : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); - caster->GetSpellHistory()->ResetCooldowns([caster](SpellHistory::CooldownStorageType::iterator itr) + caster->GetSpellHistory()->ResetCooldowns([caster, this](SpellHistory::CooldownStorageType::iterator itr) { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, GetCastDifficulty()); if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE) return false; diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 108c5aaf9f5..0a4b6fbac58 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -894,7 +894,7 @@ class spell_sha_lava_surge_proc : public SpellScriptLoader void ResetCooldown() { - GetCaster()->GetSpellHistory()->RestoreCharge(sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_LAVA_BURST)->ChargeCategoryId); + GetCaster()->GetSpellHistory()->RestoreCharge(sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_LAVA_BURST, GetCastDifficulty())->ChargeCategoryId); } void Register() override @@ -1087,9 +1087,9 @@ class spell_sha_t8_elemental_4p_bonus : public SpellScriptLoader if (!damageInfo || !damageInfo->GetDamage()) return; - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_ELECTRIFIED); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_ELECTRIFIED, GetCastDifficulty()); int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); - amount /= spellInfo->GetMaxTicks(DIFFICULTY_NONE); + amount /= spellInfo->GetMaxTicks(); // Add remaining ticks to damage done Unit* caster = eventInfo.GetActor(); @@ -1134,9 +1134,9 @@ class spell_sha_t9_elemental_4p_bonus : public SpellScriptLoader if (!damageInfo || !damageInfo->GetDamage()) return; - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE, GetCastDifficulty()); int32 amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount()); - amount /= spellInfo->GetMaxTicks(DIFFICULTY_NONE); + amount /= spellInfo->GetMaxTicks(); // Add remaining ticks to damage done Unit* caster = eventInfo.GetActor(); @@ -1226,9 +1226,9 @@ class spell_sha_t10_restoration_4p_bonus : public SpellScriptLoader if (!healInfo || !healInfo->GetHeal()) return; - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_CHAINED_HEAL); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_CHAINED_HEAL, GetCastDifficulty()); int32 amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount()); - amount /= spellInfo->GetMaxTicks(DIFFICULTY_NONE); + amount /= spellInfo->GetMaxTicks(); // Add remaining ticks to healing done Unit* caster = eventInfo.GetActor(); diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index b6da66601ee..3c8480e85f2 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -301,7 +301,7 @@ class spell_warl_demonic_circle_summon : public SpellScriptLoader // WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST; allowing him to cast the WARLOCK_DEMONIC_CIRCLE_TELEPORT. // If not in range remove the WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST. - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_WARLOCK_DEMONIC_CIRCLE_TELEPORT); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_WARLOCK_DEMONIC_CIRCLE_TELEPORT, GetCastDifficulty()); if (GetTarget()->IsWithinDist(circle, spellInfo->GetMaxRange(true))) { @@ -464,7 +464,7 @@ class spell_warl_demonic_empowerment : public SpellScriptLoader break; case CREATURE_FAMILY_VOIDWALKER: { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER, GetCastDifficulty()); int32 hp = int32(targetCreature->CountPctFromMaxHealth(GetCaster()->CalculateSpellDamage(targetCreature, spellInfo, 0))); targetCreature->CastCustomSpell(targetCreature, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER, &hp, NULL, NULL, true); break; @@ -759,7 +759,7 @@ class spell_warl_health_funnel : public SpellScriptLoader if (Player* modOwner = caster->GetSpellModOwner()) modOwner->ApplySpellMod(GetId(), SPELLMOD_COST, damage); - SpellNonMeleeDamage damageInfo(caster, caster, GetSpellInfo()->Id, GetAura()->GetSpellXSpellVisualId(), GetSpellInfo()->SchoolMask, GetAura()->GetCastGUID()); + SpellNonMeleeDamage damageInfo(caster, caster, GetSpellInfo(), GetAura()->GetSpellXSpellVisualId(), GetSpellInfo()->SchoolMask, GetAura()->GetCastGUID()); damageInfo.periodicLog = true; damageInfo.damage = damage; caster->DealSpellDamage(&damageInfo, false); diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 2693b112697..7f9be35dd77 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -1203,7 +1203,7 @@ public: //Get the Remaining Damage from the aura (if exist) int32 remainingDamage = target->GetRemainingPeriodicAmount(target->GetGUID(), SPELL_WARRIOR_TRAUMA_EFFECT, SPELL_AURA_PERIODIC_DAMAGE); //Get 25% of damage from the spell casted (Slam & Whirlwind) plus Remaining Damage from Aura - int32 damage = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()) / sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_TRAUMA_EFFECT)->GetMaxTicks(DIFFICULTY_NONE)) + remainingDamage; + int32 damage = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()) / sSpellMgr->AssertSpellInfo(SPELL_WARRIOR_TRAUMA_EFFECT, GetCastDifficulty())->GetMaxTicks()) + remainingDamage; GetCaster()->CastCustomSpell(SPELL_WARRIOR_TRAUMA_EFFECT, SPELLVALUE_BASE_POINT0, damage, target, true); } diff --git a/src/server/scripts/World/duel_reset.cpp b/src/server/scripts/World/duel_reset.cpp index 8bcf0ab0239..7ad9fb596e7 100644 --- a/src/server/scripts/World/duel_reset.cpp +++ b/src/server/scripts/World/duel_reset.cpp @@ -97,7 +97,7 @@ class DuelResetScript : public PlayerScript { SpellHistory::Clock::time_point now = GameTime::GetGameTimeSystemPoint(); uint32 cooldownDuration = itr->second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(itr->second.CooldownEnd - now).count() : 0; - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, DIFFICULTY_NONE); return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS && !itr->second.OnHold @@ -111,7 +111,7 @@ class DuelResetScript : public PlayerScript // remove cooldowns on spells that have < 10 min CD and has no onHold player->GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr) -> bool { - SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first); + SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, DIFFICULTY_NONE); return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS && !itr->second.OnHold; diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp index 67e85c2e79f..be2eae2e239 100644 --- a/src/server/scripts/World/guards.cpp +++ b/src/server/scripts/World/guards.cpp @@ -29,6 +29,7 @@ guard_shattrath_scryer EndContentData */ #include "ScriptMgr.h" +#include "CreatureAIImpl.h" #include "GuardAI.h" #include "MotionMaster.h" #include "ObjectAccessor.h" diff --git a/src/server/scripts/World/item_scripts.cpp b/src/server/scripts/World/item_scripts.cpp index 628ca0edcae..7e11fda4382 100644 --- a/src/server/scripts/World/item_scripts.cpp +++ b/src/server/scripts/World/item_scripts.cpp @@ -32,6 +32,7 @@ EndContentData */ #include "ScriptMgr.h" #include "GameObject.h" #include "Item.h" +#include "Map.h" #include "Player.h" #include "ScriptedCreature.h" #include "Spell.h" @@ -69,7 +70,7 @@ public: disabled = true; break; case 34475: - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_ARCANE_CHARGES)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_ARCANE_CHARGES, player->GetMap()->GetDifficultyID())) Spell::SendCastResult(player, spellInfo, 0, castId, SPELL_FAILED_NOT_ON_GROUND); break; } @@ -278,7 +279,7 @@ public: if (!player->GetTransport() || player->GetAreaId() != AREA_ID_SHATTERED_STRAITS) { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_PETROV_BOMB)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_PETROV_BOMB, DIFFICULTY_NONE)) Spell::SendCastResult(player, spellInfo, 0, castId, SPELL_FAILED_NOT_HERE); return true; diff --git a/src/server/scripts/World/mob_generic_creature.cpp b/src/server/scripts/World/mob_generic_creature.cpp index 613eb339b01..bc313e70eda 100644 --- a/src/server/scripts/World/mob_generic_creature.cpp +++ b/src/server/scripts/World/mob_generic_creature.cpp @@ -16,6 +16,7 @@ */ #include "ScriptMgr.h" +#include "Map.h" #include "PassiveAI.h" #include "ScriptedCreature.h" #include "SpellMgr.h" @@ -29,7 +30,7 @@ public: { trigger_periodicAI(Creature* creature) : NullCreatureAI(creature) { - spell = me->m_spells[0] ? sSpellMgr->GetSpellInfo(me->m_spells[0]) : NULL; + spell = me->m_spells[0] ? sSpellMgr->GetSpellInfo(me->m_spells[0], me->GetMap()->GetDifficultyID()) : NULL; interval = me->GetBaseAttackTime(BASE_ATTACK); timer = interval; } diff --git a/src/server/scripts/World/npc_professions.cpp b/src/server/scripts/World/npc_professions.cpp index 0d5bd2a29dc..1fd6ce702a9 100644 --- a/src/server/scripts/World/npc_professions.cpp +++ b/src/server/scripts/World/npc_professions.cpp @@ -282,11 +282,11 @@ void ProcessCastaction(Player* player, Creature* creature, uint32 spellId, uint3 bool EquippedOk(Player* player, uint32 spellId) { - SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellId); + SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!spell) return false; - for (SpellEffectInfo const* effect : spell->GetEffectsForDifficulty(DIFFICULTY_NONE)) + for (SpellEffectInfo const* effect : spell->GetEffects()) { if (!effect) continue; diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 8bc2fe634c0..095933d4c03 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -2257,7 +2257,7 @@ public: break; } - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE)) if (SpellEffectInfo const* effect0 = spellInfo->GetEffect(EFFECT_0)) if (effect0->Effect == SPELL_EFFECT_SUMMON_OBJECT_WILD) return effect0->MiscValue; |