/* * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-GPL2 * Copyright (C) 2008-2016 TrinityCore * Copyright (C) 2005-2009 MaNGOS */ #include "SpellMgr.h" #include "SpellInfo.h" #include "ObjectMgr.h" #include "SpellAuras.h" #include "SpellAuraDefines.h" #include "SharedDefines.h" #include "DBCStores.h" #include "World.h" #include "Chat.h" #include "Spell.h" #include "BattlegroundMgr.h" #include "CreatureAI.h" #include "MapManager.h" #include "BattlegroundIC.h" #include "BattlefieldWG.h" #include "BattlefieldMgr.h" #include "InstanceScript.h" #include "Player.h" #include "GameGraveyard.h" bool IsPrimaryProfessionSkill(uint32 skill) { SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill); if (!pSkill) return false; if (pSkill->categoryId != SKILL_CATEGORY_PROFESSION) return false; return true; } bool IsPartOfSkillLine(uint32 skillId, uint32 spellId) { SkillLineAbilityMapBounds skillBounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId); for (SkillLineAbilityMap::const_iterator itr = skillBounds.first; itr != skillBounds.second; ++itr) if (itr->second->skillId == skillId) return true; return false; } DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto, bool triggered) { if (spellproto->IsPositive()) return DIMINISHING_NONE; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (spellproto->Effects[i].ApplyAuraName == SPELL_AURA_MOD_TAUNT) return DIMINISHING_TAUNT; } // Explicit Diminishing Groups switch (spellproto->SpellFamilyName) { case SPELLFAMILY_GENERIC: { // Pet charge effects (Infernal Awakening, Demon Charge) if (spellproto->SpellVisual[0] == 2816 && spellproto->SpellIconID == 15) return DIMINISHING_CONTROLLED_STUN; // Gnaw else if (spellproto->Id == 47481) return DIMINISHING_CONTROLLED_STUN; // Screams of the Past else if (spellproto->Id == 7074) return DIMINISHING_NONE; break; } // Event spells case SPELLFAMILY_UNK1: return DIMINISHING_NONE; case SPELLFAMILY_MAGE: { // Frostbite if (spellproto->Id == 12494) return DIMINISHING_ROOT; // Shattered Barrier else if (spellproto->Id == 55080) return DIMINISHING_ROOT; // Deep Freeze else if (spellproto->SpellIconID == 2939 && spellproto->SpellVisual[0] == 9963) return DIMINISHING_CONTROLLED_STUN; // Frost Nova / Freeze (Water Elemental) else if (spellproto->SpellIconID == 193) return DIMINISHING_CONTROLLED_ROOT; // Dragon's Breath else if (spellproto->SpellFamilyFlags[0] & 0x800000) return DIMINISHING_DRAGONS_BREATH; break; } case SPELLFAMILY_WARRIOR: { // Hamstring - limit duration to 10s in PvP if (spellproto->SpellFamilyFlags[0] & 0x2) return DIMINISHING_LIMITONLY; // Improved Hamstring else if (spellproto->Id == 23694) return DIMINISHING_ROOT; // Charge Stun (own diminishing) else if (spellproto->SpellFamilyFlags[0] & 0x01000000) return DIMINISHING_CHARGE; break; } case SPELLFAMILY_WARLOCK: { // Curses/etc if ((spellproto->SpellFamilyFlags[0] & 0x80000000) || (spellproto->SpellFamilyFlags[1] & 0x200)) return DIMINISHING_LIMITONLY; // Seduction else if (spellproto->SpellFamilyFlags[1] & 0x10000000) return DIMINISHING_FEAR; break; } case SPELLFAMILY_DRUID: { // Pounce if (spellproto->SpellFamilyFlags[0] & 0x20000) return DIMINISHING_OPENING_STUN; // Cyclone else if (spellproto->SpellFamilyFlags[1] & 0x20) return DIMINISHING_CYCLONE; // Entangling Roots // Nature's Grasp else if (spellproto->SpellFamilyFlags[0] & 0x00000200) return DIMINISHING_CONTROLLED_ROOT; // Faerie Fire else if (spellproto->SpellFamilyFlags[0] & 0x400) return DIMINISHING_LIMITONLY; // Feral Charge Root Effect else if (spellproto->Id == 45334) return DIMINISHING_NONE; break; } case SPELLFAMILY_ROGUE: { // Gouge if (spellproto->SpellFamilyFlags[0] & 0x8) return DIMINISHING_DISORIENT; // Blind else if (spellproto->SpellFamilyFlags[0] & 0x1000000) return DIMINISHING_FEAR; // Cheap Shot else if (spellproto->SpellFamilyFlags[0] & 0x400) return DIMINISHING_OPENING_STUN; // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags) else if (spellproto->SpellIconID == 163) return DIMINISHING_LIMITONLY; break; } case SPELLFAMILY_HUNTER: { // Hunter's Mark if ((spellproto->SpellFamilyFlags[0] & 0x400) && spellproto->SpellIconID == 538) return DIMINISHING_LIMITONLY; // Scatter Shot (own diminishing) else if ((spellproto->SpellFamilyFlags[0] & 0x40000) && spellproto->SpellIconID == 132) return DIMINISHING_SCATTER_SHOT; // Entrapment (own diminishing) else if (spellproto->SpellVisual[0] == 7484 && spellproto->SpellIconID == 20) return DIMINISHING_ENTRAPMENT; // Wyvern Sting mechanic is MECHANIC_SLEEP but the diminishing is DIMINISHING_DISORIENT else if ((spellproto->SpellFamilyFlags[1] & 0x1000) && spellproto->SpellIconID == 1721) return DIMINISHING_DISORIENT; // Freezing Arrow else if (spellproto->SpellFamilyFlags[0] & 0x8) return DIMINISHING_DISORIENT; break; } case SPELLFAMILY_PALADIN: { // Judgement of Justice - limit duration to 10s in PvP if (spellproto->SpellFamilyFlags[0] & 0x100000) return DIMINISHING_LIMITONLY; // Turn Evil else if ((spellproto->SpellFamilyFlags[1] & 0x804000) && spellproto->SpellIconID == 309) return DIMINISHING_FEAR; break; } case SPELLFAMILY_SHAMAN: { // Storm, Earth and Fire - Earthgrab if (spellproto->SpellFamilyFlags[2] & 0x4000) return DIMINISHING_NONE; break; } case SPELLFAMILY_DEATHKNIGHT: { // Hungering Cold (no flags) if (spellproto->SpellIconID == 2797) return DIMINISHING_DISORIENT; // Mark of Blood else if ((spellproto->SpellFamilyFlags[0] & 0x10000000) && spellproto->SpellIconID == 2285) return DIMINISHING_LIMITONLY; break; } default: break; } // Lastly - Set diminishing depending on mechanic uint32 mechanic = spellproto->GetAllEffectsMechanicMask(); if (mechanic & (1 << MECHANIC_CHARM)) return DIMINISHING_MIND_CONTROL; if (mechanic & (1 << MECHANIC_SILENCE)) return DIMINISHING_SILENCE; if (mechanic & (1 << MECHANIC_SLEEP)) return DIMINISHING_SLEEP; if (mechanic & ((1 << MECHANIC_SAPPED) | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_SHACKLE))) return DIMINISHING_DISORIENT; // Mechanic Knockout, except Blast Wave if (mechanic & (1 << MECHANIC_KNOCKOUT) && spellproto->SpellIconID != 292) return DIMINISHING_DISORIENT; if (mechanic & (1 << MECHANIC_DISARM)) return DIMINISHING_DISARM; if (mechanic & (1 << MECHANIC_FEAR)) return DIMINISHING_FEAR; if (mechanic & (1 << MECHANIC_STUN)) return triggered ? DIMINISHING_STUN : DIMINISHING_CONTROLLED_STUN; if (mechanic & (1 << MECHANIC_BANISH)) return DIMINISHING_BANISH; if (mechanic & (1 << MECHANIC_ROOT)) return triggered ? DIMINISHING_ROOT : DIMINISHING_CONTROLLED_ROOT; if (mechanic & (1 << MECHANIC_HORROR)) return DIMINISHING_HORROR; return DIMINISHING_NONE; } DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group) { switch (group) { case DIMINISHING_TAUNT: case DIMINISHING_CONTROLLED_STUN: case DIMINISHING_STUN: case DIMINISHING_OPENING_STUN: case DIMINISHING_CYCLONE: case DIMINISHING_CHARGE: return DRTYPE_ALL; case DIMINISHING_LIMITONLY: case DIMINISHING_NONE: return DRTYPE_NONE; default: return DRTYPE_PLAYER; } } DiminishingLevels GetDiminishingReturnsMaxLevel(DiminishingGroup group) { switch (group) { case DIMINISHING_TAUNT: return DIMINISHING_LEVEL_TAUNT_IMMUNE; default: return DIMINISHING_LEVEL_IMMUNE; } } int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const* spellproto) { if (!IsDiminishingReturnsGroupDurationLimited(group)) return 0; // Explicit diminishing duration switch (spellproto->SpellFamilyName) { case SPELLFAMILY_DRUID: { // Faerie Fire - limit to 40 seconds in PvP (3.1) if (spellproto->SpellFamilyFlags[0] & 0x400) return 40 * IN_MILLISECONDS; break; } case SPELLFAMILY_HUNTER: { // Wyvern Sting if (spellproto->SpellFamilyFlags[1] & 0x1000) return 6 * IN_MILLISECONDS; // Hunter's Mark if (spellproto->SpellFamilyFlags[0] & 0x400) return 120 * IN_MILLISECONDS; break; } case SPELLFAMILY_PALADIN: { // Repentance - limit to 6 seconds in PvP if (spellproto->SpellFamilyFlags[0] & 0x4) return 6 * IN_MILLISECONDS; break; } case SPELLFAMILY_WARLOCK: { // Banish - limit to 6 seconds in PvP if (spellproto->SpellFamilyFlags[1] & 0x8000000) return 6 * IN_MILLISECONDS; // Curse of Tongues - limit to 12 seconds in PvP else if (spellproto->SpellFamilyFlags[2] & 0x800) return 12 * IN_MILLISECONDS; // Curse of Elements - limit to 120 seconds in PvP else if (spellproto->SpellFamilyFlags[1] & 0x200) return 120 * IN_MILLISECONDS; // Curse of Exhaustion else if (spellproto->SpellFamilyFlags[0] & 0x400000) return 12 * IN_MILLISECONDS; break; } default: break; } return 10 * IN_MILLISECONDS; } bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group) { switch (group) { case DIMINISHING_BANISH: case DIMINISHING_CONTROLLED_STUN: case DIMINISHING_CONTROLLED_ROOT: case DIMINISHING_CYCLONE: case DIMINISHING_DISORIENT: case DIMINISHING_ENTRAPMENT: case DIMINISHING_FEAR: case DIMINISHING_HORROR: case DIMINISHING_MIND_CONTROL: case DIMINISHING_OPENING_STUN: case DIMINISHING_ROOT: case DIMINISHING_STUN: case DIMINISHING_SLEEP: case DIMINISHING_LIMITONLY: return true; default: return false; } } SpellMgr::SpellMgr() { } SpellMgr::~SpellMgr() { UnloadSpellInfoStore(); } SpellMgr* SpellMgr::instance() { static SpellMgr instance; return &instance; } /// Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book, etc bool SpellMgr::ComputeIsSpellValid(SpellInfo const* spellInfo, bool msg) { // not exist if (!spellInfo) return false; bool need_check_reagents = false; // check effects for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { switch (spellInfo->Effects[i].Effect) { case 0: continue; // craft spell for crafting non-existed item (break client recipes list show) case SPELL_EFFECT_CREATE_ITEM: case SPELL_EFFECT_CREATE_ITEM_2: { if (spellInfo->Effects[i].ItemType == 0) { // skip auto-loot crafting spells, its not need explicit item info (but have special fake items sometime) if (!spellInfo->IsLootCrafting()) { if (msg) sLog->outErrorDb("Craft spell %u not have create item entry.", spellInfo->Id); return false; } } // also possible IsLootCrafting case but fake item must exist anyway else if (!sObjectMgr->GetItemTemplate(spellInfo->Effects[i].ItemType)) { if (msg) sLog->outErrorDb("Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType); return false; } need_check_reagents = true; break; } case SPELL_EFFECT_LEARN_SPELL: { SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell); if (!ComputeIsSpellValid(spellInfo2, msg)) { if (msg) sLog->outErrorDb("Spell %u learn to invalid spell %u, and then...", spellInfo->Id, spellInfo->Effects[i].TriggerSpell); return false; } break; } } } if (need_check_reagents) { for (uint8 j = 0; j < MAX_SPELL_REAGENTS; ++j) { if (spellInfo->Reagent[j] > 0 && !sObjectMgr->GetItemTemplate(spellInfo->Reagent[j])) { if (msg) sLog->outErrorDb("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]); return false; } } } return true; } bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo) { if (!spellInfo) return false; return spellInfo->IsSpellValid(); } void DeleteSpellFromAllPlayers(uint32 spellId) { CharacterDatabaseStatements stmts[2] = {CHAR_DEL_INVALID_SPELL_SPELLS, CHAR_DEL_INVALID_SPELL_TALENTS}; for (uint8 i = 0; i < 2; i++) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(stmts[i]); stmt->setUInt32(0, spellId); CharacterDatabase.Execute(stmt); } } bool SpellMgr::CheckSpellValid(SpellInfo const* spellInfo, uint32 spellId, bool isTalent) { if (!spellInfo) { DeleteSpellFromAllPlayers(spellId); sLog->outError("Player::%s: Non-existed in SpellStore spell #%u request.", (isTalent ? "AddTalent" : "addSpell"), spellId); return false; } if (!IsSpellValid(spellInfo)) { DeleteSpellFromAllPlayers(spellId); sLog->outError("Player::%s: Broken spell #%u learning not allowed.", (isTalent ? "AddTalent" : "addSpell"), spellId); return false; } return true; } uint32 SpellMgr::GetSpellDifficultyId(uint32 spellId) const { SpellDifficultySearcherMap::const_iterator i = mSpellDifficultySearcherMap.find(spellId); return i == mSpellDifficultySearcherMap.end() ? 0 : (*i).second; } void SpellMgr::SetSpellDifficultyId(uint32 spellId, uint32 id) { mSpellDifficultySearcherMap[spellId] = id; } uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const { if (!GetSpellInfo(spellId)) return spellId; if (!caster || !caster->GetMap() || !caster->GetMap()->IsDungeon()) return spellId; uint32 mode = uint32(caster->GetMap()->GetSpawnMode()); if (mode >= MAX_DIFFICULTY) { sLog->outError("SpellMgr::GetSpellIdForDifficulty: Incorrect Difficulty for spell %u.", spellId); return spellId; //return source spell } uint32 difficultyId = GetSpellDifficultyId(spellId); if (!difficultyId) return spellId; //return source spell, it has only REGULAR_DIFFICULTY SpellDifficultyEntry const* difficultyEntry = sSpellDifficultyStore.LookupEntry(difficultyId); if (!difficultyEntry) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SpellMgr::GetSpellIdForDifficulty: SpellDifficultyEntry not found for spell %u. This should never happen.", spellId); #endif return spellId; //return source spell } if (difficultyEntry->SpellID[mode] <= 0 && mode > DUNGEON_DIFFICULTY_HEROIC) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is NULL, using mode %u", spellId, mode, mode - 2); #endif mode -= 2; } if (difficultyEntry->SpellID[mode] <= 0) { sLog->outErrorDb("SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is 0. Check spelldifficulty_dbc!", spellId, mode); return spellId; } #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SpellMgr::GetSpellIdForDifficulty: spellid for spell %u in mode %u is %d", spellId, mode, difficultyEntry->SpellID[mode]); #endif return uint32(difficultyEntry->SpellID[mode]); } SpellInfo const* SpellMgr::GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const { uint32 newSpellId = GetSpellIdForDifficulty(spell->Id, caster); SpellInfo const* newSpell = GetSpellInfo(newSpellId); if (!newSpell) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SpellMgr::GetSpellForDifficultyFromSpell: spell %u not found. Check spelldifficulty_dbc!", newSpellId); #endif return spell; } #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SpellMgr::GetSpellForDifficultyFromSpell: Spell id for instance mode is %u (original %u)", newSpell->Id, spell->Id); #endif return newSpell; } SpellChainNode const* SpellMgr::GetSpellChainNode(uint32 spell_id) const { SpellChainMap::const_iterator itr = mSpellChains.find(spell_id); if (itr == mSpellChains.end()) return nullptr; return &itr->second; } uint32 SpellMgr::GetFirstSpellInChain(uint32 spell_id) const { if (SpellChainNode const* node = GetSpellChainNode(spell_id)) return node->first->Id; return spell_id; } uint32 SpellMgr::GetLastSpellInChain(uint32 spell_id) const { if (SpellChainNode const* node = GetSpellChainNode(spell_id)) return node->last->Id; return spell_id; } uint32 SpellMgr::GetNextSpellInChain(uint32 spell_id) const { if (SpellChainNode const* node = GetSpellChainNode(spell_id)) if (node->next) return node->next->Id; return 0; } uint32 SpellMgr::GetPrevSpellInChain(uint32 spell_id) const { if (SpellChainNode const* node = GetSpellChainNode(spell_id)) if (node->prev) return node->prev->Id; return 0; } uint8 SpellMgr::GetSpellRank(uint32 spell_id) const { if (SpellChainNode const* node = GetSpellChainNode(spell_id)) return node->rank; return 0; } uint32 SpellMgr::GetSpellWithRank(uint32 spell_id, uint32 rank, bool strict) const { if (SpellChainNode const* node = GetSpellChainNode(spell_id)) { if (rank != node->rank) return GetSpellWithRank(node->rank < rank ? node->next->Id : node->prev->Id, rank, strict); } else if (strict && rank > 1) return 0; return spell_id; } SpellRequiredMapBounds SpellMgr::GetSpellsRequiredForSpellBounds(uint32 spell_id) const { return mSpellReq.equal_range(spell_id); } SpellsRequiringSpellMapBounds SpellMgr::GetSpellsRequiringSpellBounds(uint32 spell_id) const { return mSpellsReqSpell.equal_range(spell_id); } bool SpellMgr::IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const { SpellsRequiringSpellMapBounds spellsRequiringSpell = GetSpellsRequiringSpellBounds(req_spellid); for (SpellsRequiringSpellMap::const_iterator itr = spellsRequiringSpell.first; itr != spellsRequiringSpell.second; ++itr) { if (itr->second == spellid) return true; } return false; } bool SpellMgr::IsAdditionalTalentSpell(uint32 spellId) const { return mTalentSpellAdditionalSet.find(spellId) != mTalentSpellAdditionalSet.end(); } SpellLearnSkillNode const* SpellMgr::GetSpellLearnSkill(uint32 spell_id) const { SpellLearnSkillMap::const_iterator itr = mSpellLearnSkills.find(spell_id); if (itr != mSpellLearnSkills.end()) return &itr->second; else return nullptr; } SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const { SpellTargetPositionMap::const_iterator itr = mSpellTargetPositions.find(std::make_pair(spell_id, effIndex)); if (itr != mSpellTargetPositions.end()) return &itr->second; return nullptr; } SpellGroupStackFlags SpellMgr::GetGroupStackFlags(uint32 groupid) const { SpellGroupStackMap::const_iterator itr = mSpellGroupStackMap.find(groupid); if (itr != mSpellGroupStackMap.end()) return itr->second; return SPELL_GROUP_STACK_FLAG_NONE; } uint32 SpellMgr::GetSpellGroup(uint32 spell_id) const { uint32 first_rank = GetFirstSpellInChain(spell_id); SpellGroupMap::const_iterator itr = mSpellGroupMap.find(first_rank); if (itr != mSpellGroupMap.end()) return itr->second.groupId; return 0; } SpellGroupSpecialFlags SpellMgr::GetSpellGroupSpecialFlags(uint32 spell_id) const { uint32 first_rank = GetFirstSpellInChain(spell_id); SpellGroupMap::const_iterator itr = mSpellGroupMap.find(first_rank); if (itr != mSpellGroupMap.end()) return itr->second.specialFlags; return SPELL_GROUP_SPECIAL_FLAG_NONE; } SpellGroupStackFlags SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const { uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id; uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id; // xinef: dunno why i added this if (spellid_1 == spellid_2 && remove && !areaAura) return SPELL_GROUP_STACK_FLAG_NONE; uint32 groupId = GetSpellGroup(spellid_1); if (groupId > 0 && groupId == GetSpellGroup(spellid_2)) { SpellGroupSpecialFlags flag1 = GetSpellGroupSpecialFlags(spellid_1); SpellGroupSpecialFlags flag2 = GetSpellGroupSpecialFlags(spellid_2); SpellGroupStackFlags additionFlag = SPELL_GROUP_STACK_FLAG_NONE; // xinef: first flags are used for elixir stacking rules if (flag1 & SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX && flag2 & SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX) { if (flag1 & flag2) return SPELL_GROUP_STACK_FLAG_NEVER_STACK; } // xinef: check only flag1 (new spell) else if (flag1 & SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST) additionFlag = SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST; else if (flag2 & SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST) additionFlag = SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST; return SpellGroupStackFlags(GetGroupStackFlags(groupId) | additionFlag); } return SPELL_GROUP_STACK_FLAG_NONE; } void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set& availableElixirs) const { for (SpellGroupMap::const_iterator itr = mSpellGroupMap.begin(); itr != mSpellGroupMap.end(); ++itr) if (itr->second.groupId == group_id && itr->second.specialFlags == flag) availableElixirs.insert(itr->first); // insert spell id } SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const { SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId); if (itr != mSpellProcEventMap.end()) return &itr->second; return nullptr; } bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const { // No extra req need uint32 procEvent_procEx = PROC_EX_NONE; // check prockFlags for condition if ((procFlags & EventProcFlag) == 0) return false; // Xinef: Always trigger for this, including TAKEN_DAMAGE if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH | PROC_FLAG_TAKEN_DAMAGE)) return true; bool hasFamilyMask = false; if (procFlags & PROC_FLAG_DONE_PERIODIC) { if (procExtra & PROC_EX_INTERNAL_HOT) { if (EventProcFlag == PROC_FLAG_DONE_PERIODIC) { /// no aura with only PROC_FLAG_DONE_PERIODIC and spellFamilyName == 0 can proc from a HOT. if (!spellProto->SpellFamilyName) return false; } /// Aura must have positive procflags for a HOT to proc else if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS))) return false; } /// Aura must have negative or neutral(PROC_FLAG_DONE_PERIODIC only) procflags for a DOT to proc else if (EventProcFlag != PROC_FLAG_DONE_PERIODIC) if (!(EventProcFlag & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | PROC_FLAG_DONE_TRAP_ACTIVATION))) return false; } if (procFlags & PROC_FLAG_TAKEN_PERIODIC) { if (procExtra & PROC_EX_INTERNAL_HOT) { /// No aura that only has PROC_FLAG_TAKEN_PERIODIC can proc from a HOT. if (EventProcFlag == PROC_FLAG_TAKEN_PERIODIC) return false; /// Aura must have positive procflags for a HOT to proc if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS))) return false; } /// Aura must have negative or neutral(PROC_FLAG_TAKEN_PERIODIC only) procflags for a DOT to proc else if (EventProcFlag != PROC_FLAG_TAKEN_PERIODIC) if (!(EventProcFlag & (PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG))) return false; } // Trap casts are active by default if (procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION) active = true; if (spellProcEvent) // Exist event data { // Store extra req procEvent_procEx = spellProcEvent->procEx; // For melee triggers if (procSpell == nullptr) { // Check (if set) for school (melee attack have Normal school) if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) return false; } else // For spells need check school/spell family/family mask { // Check (if set) for school if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpell->SchoolMask) == 0) return false; // Check (if set) for spellFamilyName if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName)) return false; // spellFamilyName is Ok need check for spellFamilyMask if present if (spellProcEvent->spellFamilyMask) { if (!(spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags)) return false; hasFamilyMask = true; // Some spells are not considered as active even with have spellfamilyflags if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)) active = true; } } } if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY)) { if (!hasFamilyMask) return false; } // Check for extra req (if none) and hit/crit if (procEvent_procEx == PROC_EX_NONE) { // No extra req, so can trigger only for hit/crit - spell has to be active if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && active) return true; } else // Passive spells hits here only if resist/reflect/immune/evade { if (procExtra & AURA_SPELL_PROC_EX_MASK) { // if spell marked as procing only from not active spells if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL) return false; // if spell marked as procing only from active spells if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL) return false; // Exist req for PROC_EX_EX_TRIGGER_ALWAYS if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS) return true; // PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK)) == 0)) return true; } // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other) if (procEvent_procEx & procExtra) return true; } return false; } SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const { SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId); if (itr != mSpellProcMap.end()) return &itr->second; return nullptr; } bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const { // proc type doesn't match if (!(eventInfo.GetTypeMask() & procEntry.typeMask)) return false; // check XP or honor target requirement if (procEntry.attributesMask & PROC_ATTR_REQ_EXP_OR_HONOR) if (Player* actor = eventInfo.GetActor()->ToPlayer()) if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget())) return false; // always trigger for these types if (eventInfo.GetTypeMask() & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH)) return true; // check school mask (if set) for other trigger types if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask)) return false; // check spell family name/flags (if set) for spells if (eventInfo.GetTypeMask() & (PERIODIC_PROC_FLAG_MASK | SPELL_PROC_FLAG_MASK | PROC_FLAG_DONE_TRAP_ACTIVATION)) { if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName)) return false; if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags)) return false; } // check spell type mask (if set) if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)) { if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask)) return false; } // check spell phase mask if (eventInfo.GetTypeMask() & REQ_SPELL_PHASE_PROC_FLAG_MASK) { if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask)) return false; } // check hit mask (on taken hit or on done hit, but not on spell cast phase) if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST))) { uint32 hitMask = procEntry.hitMask; // get default values if hit mask not set if (!hitMask) { // for taken procs allow normal + critical hits by default if (eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) hitMask |= PROC_HIT_NORMAL | PROC_HIT_CRITICAL; // for done procs allow normal + critical + absorbs by default else hitMask |= PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB; } if (!(eventInfo.GetHitMask() & hitMask)) return false; } return true; } SpellBonusEntry const* SpellMgr::GetSpellBonusData(uint32 spellId) const { // Lookup data SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId); if (itr != mSpellBonusMap.end()) return &itr->second; // Not found, try lookup for 1 spell rank if exist if (uint32 rank_1 = GetFirstSpellInChain(spellId)) { SpellBonusMap::const_iterator itr2 = mSpellBonusMap.find(rank_1); if (itr2 != mSpellBonusMap.end()) return &itr2->second; } return nullptr; } SpellThreatEntry const* SpellMgr::GetSpellThreatEntry(uint32 spellID) const { SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellID); if (itr != mSpellThreatMap.end()) return &itr->second; else { uint32 firstSpell = GetFirstSpellInChain(spellID); itr = mSpellThreatMap.find(firstSpell); if (itr != mSpellThreatMap.end()) return &itr->second; } return nullptr; } float SpellMgr::GetSpellMixologyBonus(uint32 spellId) const { SpellMixologyMap::const_iterator itr = mSpellMixologyMap.find(spellId); if (itr == mSpellMixologyMap.end()) return 30.0f; return itr->second; } SkillLineAbilityMapBounds SpellMgr::GetSkillLineAbilityMapBounds(uint32 spell_id) const { return mSkillLineAbilityMap.equal_range(spell_id); } PetAura const* SpellMgr::GetPetAura(uint32 spell_id, uint8 eff) const { SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find((spell_id << 8) + eff); if (itr != mSpellPetAuraMap.end()) return &itr->second; else return nullptr; } SpellEnchantProcEntry const* SpellMgr::GetSpellEnchantProcEvent(uint32 enchId) const { SpellEnchantProcEventMap::const_iterator itr = mSpellEnchantProcEventMap.find(enchId); if (itr != mSpellEnchantProcEventMap.end()) return &itr->second; return nullptr; } bool SpellMgr::IsArenaAllowedEnchancment(uint32 ench_id) const { return mEnchantCustomAttr[ench_id]; } const std::vector* SpellMgr::GetSpellLinked(int32 spell_id) const { SpellLinkedMap::const_iterator itr = mSpellLinkedMap.find(spell_id); return itr != mSpellLinkedMap.end() ? &(itr->second) : nullptr; } PetLevelupSpellSet const* SpellMgr::GetPetLevelupSpellList(uint32 petFamily) const { PetLevelupSpellMap::const_iterator itr = mPetLevelupSpellMap.find(petFamily); if (itr != mPetLevelupSpellMap.end()) return &itr->second; else return nullptr; } PetDefaultSpellsEntry const* SpellMgr::GetPetDefaultSpellsEntry(int32 id) const { PetDefaultSpellsMap::const_iterator itr = mPetDefaultSpellsMap.find(id); if (itr != mPetDefaultSpellsMap.end()) return &itr->second; return nullptr; } SpellAreaMapBounds SpellMgr::GetSpellAreaMapBounds(uint32 spell_id) const { return mSpellAreaMap.equal_range(spell_id); } SpellAreaForQuestMapBounds SpellMgr::GetSpellAreaForQuestMapBounds(uint32 quest_id) const { return mSpellAreaForQuestMap.equal_range(quest_id); } SpellAreaForQuestMapBounds SpellMgr::GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const { return mSpellAreaForQuestEndMap.equal_range(quest_id); } SpellAreaForAuraMapBounds SpellMgr::GetSpellAreaForAuraMapBounds(uint32 spell_id) const { return mSpellAreaForAuraMap.equal_range(spell_id); } SpellAreaForAreaMapBounds SpellMgr::GetSpellAreaForAreaMapBounds(uint32 area_id) const { return mSpellAreaForAreaMap.equal_range(area_id); } bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const { if (gender != GENDER_NONE) // not in expected gender if (!player || gender != player->getGender()) return false; if (raceMask) // not in expected race if (!player || !(raceMask & player->getRaceMask())) return false; if (areaId) // not in expected zone if (newZone != areaId && newArea != areaId) return false; if (questStart) // not in expected required quest state if (!player || (((1 << player->GetQuestStatus(questStart)) & questStartStatus) == 0)) return false; if (questEnd) // not in expected forbidden quest state if (!player || (((1 << player->GetQuestStatus(questEnd)) & questEndStatus) == 0)) return false; if (auraSpell) // not have expected aura if (!player || (auraSpell > 0 && !player->HasAura(auraSpell)) || (auraSpell < 0 && player->HasAura(-auraSpell))) return false; // Extra conditions -- leaving the possibility add extra conditions... switch (spellId) { case 58600: // No fly Zone - Dalaran { if (!player) return false; AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(player->GetAreaId()); if (!(pArea && pArea->flags & AREA_FLAG_NO_FLY_ZONE)) return false; if (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY)) return false; // Xinef: Underbelly elixir if (player->GetPositionZ() < 637.0f && player->HasAuraType(SPELL_AURA_TRANSFORM)) return false; break; } case 58730: // No fly Zone - Wintergrasp { if (!player) return false; Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId()); if (!Bf || Bf->CanFlyIn() || (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY))) return false; break; } // xinef: northrend flying mounts // xinef: NE wisp and spectral gryphon case 55164: case 55173: { Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId()); return !Bf || Bf->CanFlyIn(); } case 57940: // Essence of Wintergrasp OUTSIDE case 58045: // Essence of Wintergrasp INSIDE { if (!player) return false; Battlefield* Bf = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); if (!Bf || player->GetTeamId() != Bf->GetDefenderTeam() || Bf->IsWarTime()) return false; break; } case 74411: // Battleground - Dampening { if (!player) return false; if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId())) return bf->IsWarTime(); break; } case 68719: // Oil Refinery - Isle of Conquest. case 68720: // Quarry - Isle of Conquest. { if (!player) return false; Battleground* bg = player->GetBattleground(); if (!bg || bg->GetBgTypeID(true) != BATTLEGROUND_IC) return false; uint8 nodeType = spellId == 68719 ? NODE_TYPE_REFINERY : NODE_TYPE_QUARRY; uint8 nodeState = player->GetTeamId() == TEAM_ALLIANCE ? NODE_STATE_CONTROLLED_A : NODE_STATE_CONTROLLED_H; return bg->ToBattlegroundIC()->GetNodeState(nodeType) == nodeState; } case 56618: // Horde Controls Factory Phase Shift case 56617: // Alliance Controls Factory Phase Shift { if (!player) return false; Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId()); if (!bf || bf->GetTypeId() != BATTLEFIELD_WG) return false; // team that controls the workshop in the specified area uint32 team = bf->GetData(newArea); if (team == TEAM_HORDE) return spellId == 56618; else if (team == TEAM_ALLIANCE) return spellId == 56617; break; } // Hellscream's Warsong case 73816: case 73818: case 73819: case 73820: case 73821: case 73822: // Strength of Wrynn case 73762: case 73824: case 73825: case 73826: case 73827: case 73828: if (player) if (InstanceScript* s = const_cast(player)->GetInstanceScript()) return s->GetData(251 /*DATA_BUFF_AVAILABLE*/) != 0; return false; break; } return true; } void SpellMgr::UnloadSpellInfoChains() { for (SpellChainMap::iterator itr = mSpellChains.begin(); itr != mSpellChains.end(); ++itr) mSpellInfoMap[itr->first]->ChainEntry = nullptr; mSpellChains.clear(); } void SpellMgr::LoadSpellTalentRanks() { // cleanup core data before reload - remove reference to ChainNode from SpellInfo UnloadSpellInfoChains(); for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) { TalentEntry const* talentInfo = sTalentStore.LookupEntry(i); if (!talentInfo) continue; SpellInfo const* lastSpell = nullptr; for (uint8 rank = MAX_TALENT_RANK - 1; rank > 0; --rank) { if (talentInfo->RankID[rank]) { lastSpell = GetSpellInfo(talentInfo->RankID[rank]); break; } } if (!lastSpell) continue; SpellInfo const* firstSpell = GetSpellInfo(talentInfo->RankID[0]); if (!firstSpell) { sLog->outErrorDb("SpellMgr::LoadSpellTalentRanks: First Rank Spell %u for TalentEntry %u does not exist.", talentInfo->RankID[0], i); continue; } SpellInfo const* prevSpell = nullptr; for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank) { uint32 spellId = talentInfo->RankID[rank]; if (!spellId) break; SpellInfo const* currentSpell = GetSpellInfo(spellId); if (!currentSpell) { sLog->outErrorDb("SpellMgr::LoadSpellTalentRanks: Spell %u (Rank: %u) for TalentEntry %u does not exist.", spellId, rank + 1, i); break; } SpellChainNode node; node.first = firstSpell; node.last = lastSpell; node.rank = rank + 1; node.prev = prevSpell; node.next = node.rank < MAX_TALENT_RANK ? GetSpellInfo(talentInfo->RankID[node.rank]) : nullptr; mSpellChains[spellId] = node; mSpellInfoMap[spellId]->ChainEntry = &mSpellChains[spellId]; prevSpell = currentSpell; } } } void SpellMgr::LoadSpellRanks() { // cleanup data and load spell ranks for talents from dbc LoadSpellTalentRanks(); uint32 oldMSTime = getMSTime(); // 0 1 2 QueryResult result = WorldDatabase.Query("SELECT first_spell_id, spell_id, `rank` from spell_ranks ORDER BY first_spell_id, `rank`"); if (!result) { sLog->outString(">> Loaded 0 spell rank records. DB table `spell_ranks` is empty."); sLog->outString(); return; } uint32 count = 0; bool finished = false; do { // spellid, rank std::list < std::pair < int32, int32 > > rankChain; int32 currentSpell = -1; int32 lastSpell = -1; // fill one chain while (currentSpell == lastSpell && !finished) { Field* fields = result->Fetch(); currentSpell = fields[0].GetUInt32(); if (lastSpell == -1) lastSpell = currentSpell; uint32 spell_id = fields[1].GetUInt32(); uint32 rank = fields[2].GetUInt8(); // don't drop the row if we're moving to the next rank if (currentSpell == lastSpell) { rankChain.push_back(std::make_pair(spell_id, rank)); if (!result->NextRow()) finished = true; } else break; } // check if chain is made with valid first spell SpellInfo const* first = GetSpellInfo(lastSpell); if (!first) { sLog->outErrorDb("Spell rank identifier(first_spell_id) %u listed in `spell_ranks` does not exist!", lastSpell); continue; } // check if chain is long enough if (rankChain.size() < 2) { sLog->outErrorDb("There is only 1 spell rank for identifier(first_spell_id) %u in `spell_ranks`, entry is not needed!", lastSpell); continue; } int32 curRank = 0; bool valid = true; // check spells in chain for (std::list >::iterator itr = rankChain.begin(); itr != rankChain.end(); ++itr) { SpellInfo const* spell = GetSpellInfo(itr->first); if (!spell) { sLog->outErrorDb("Spell %u (rank %u) listed in `spell_ranks` for chain %u does not exist!", itr->first, itr->second, lastSpell); valid = false; break; } ++curRank; if (itr->second != curRank) { sLog->outErrorDb("Spell %u (rank %u) listed in `spell_ranks` for chain %u does not have proper rank value(should be %u)!", itr->first, itr->second, lastSpell, curRank); valid = false; break; } } if (!valid) continue; int32 prevRank = 0; // insert the chain std::list >::iterator itr = rankChain.begin(); do { ++count; int32 addedSpell = itr->first; mSpellChains[addedSpell].first = GetSpellInfo(lastSpell); mSpellChains[addedSpell].last = GetSpellInfo(rankChain.back().first); mSpellChains[addedSpell].rank = itr->second; mSpellChains[addedSpell].prev = GetSpellInfo(prevRank); mSpellInfoMap[addedSpell]->ChainEntry = &mSpellChains[addedSpell]; prevRank = addedSpell; ++itr; if (itr == rankChain.end()) { mSpellChains[addedSpell].next = nullptr; break; } else mSpellChains[addedSpell].next = GetSpellInfo(itr->first); } while (true); } while (!finished); sLog->outString(">> Loaded %u spell rank records in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellRequired() { uint32 oldMSTime = getMSTime(); mSpellsReqSpell.clear(); // need for reload case mSpellReq.clear(); // need for reload case // 0 1 QueryResult result = WorldDatabase.Query("SELECT spell_id, req_spell from spell_required"); if (!result) { sLog->outString(">> Loaded 0 spell required records. DB table `spell_required` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 spellId = fields[0].GetUInt32(); uint32 spellReq = fields[1].GetUInt32(); // check if chain is made with valid first spell SpellInfo const* spellInfo = GetSpellInfo(spellId); if (!spellInfo) { sLog->outErrorDb("spell_id %u in `spell_required` table is not found in dbcs, skipped", spellId); continue; } SpellInfo const* reqSpellInfo = GetSpellInfo(spellReq); if (!reqSpellInfo) { sLog->outErrorDb("req_spell %u in `spell_required` table is not found in dbcs, skipped", spellReq); continue; } if (GetFirstSpellInChain(spellId) == GetFirstSpellInChain(spellReq)) { sLog->outErrorDb("req_spell %u and spell_id %u in `spell_required` table are ranks of the same spell, entry not needed, skipped", spellReq, spellId); continue; } if (IsSpellRequiringSpell(spellId, spellReq)) { sLog->outErrorDb("duplicated entry of req_spell %u and spell_id %u in `spell_required`, skipped", spellReq, spellId); continue; } mSpellReq.insert (std::pair(spellId, spellReq)); mSpellsReqSpell.insert (std::pair(spellReq, spellId)); ++count; // xinef: fill additionalTalentInfo data, currently Blessing of Sanctuary only if (GetTalentSpellCost(spellReq) > 0) mTalentSpellAdditionalSet.insert(spellId); } while (result->NextRow()); sLog->outString(">> Loaded %u spell required records in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellLearnSkills() { uint32 oldMSTime = getMSTime(); mSpellLearnSkills.clear(); // need for reload case // search auto-learned skills and add its to map also for use in unlearn spells/talents uint32 dbc_count = 0; for (uint32 spell = 0; spell < GetSpellInfoStoreSize(); ++spell) { SpellInfo const* entry = GetSpellInfo(spell); if (!entry) continue; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (entry->Effects[i].Effect == SPELL_EFFECT_SKILL) { SpellLearnSkillNode dbc_node; dbc_node.skill = entry->Effects[i].MiscValue; dbc_node.step = entry->Effects[i].CalcValue(); if (dbc_node.skill != SKILL_RIDING) dbc_node.value = 1; else dbc_node.value = dbc_node.step * 75; dbc_node.maxvalue = dbc_node.step * 75; mSpellLearnSkills[spell] = dbc_node; ++dbc_count; break; } } } sLog->outString(">> Loaded %u Spell Learn Skills from DBC in %u ms", dbc_count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellTargetPositions() { uint32 oldMSTime = getMSTime(); mSpellTargetPositions.clear(); // need for reload case // 0 1 2 3 4 5 6 QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, MapID, PositionX, PositionY, PositionZ, Orientation FROM spell_target_position"); if (!result) { sLog->outString(">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 Spell_ID = fields[0].GetUInt32(); SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8()); SpellTargetPosition st; st.target_mapId = fields[2].GetUInt16(); st.target_X = fields[3].GetFloat(); st.target_Y = fields[4].GetFloat(); st.target_Z = fields[5].GetFloat(); st.target_Orientation = fields[6].GetFloat(); MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId); if (!mapEntry) { sLog->outErrorDb("Spell (Id: %u, effIndex: %u) target map (ID: %u) does not exist in `Map.dbc`.", Spell_ID, effIndex, st.target_mapId); continue; } if (st.target_X == 0 && st.target_Y == 0 && st.target_Z == 0) { sLog->outErrorDb("Spell (Id: %u, effIndex: %u) target coordinates not provided.", Spell_ID, effIndex); continue; } SpellInfo const* spellInfo = GetSpellInfo(Spell_ID); if (!spellInfo) { sLog->outErrorDb("Spell (ID:%u) listed in `spell_target_position` does not exist.", Spell_ID); continue; } if (spellInfo->Effects[effIndex].TargetA.GetTarget() == TARGET_DEST_DB || spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DB) { std::pair key = std::make_pair(Spell_ID, effIndex); mSpellTargetPositions[key] = st; ++count; } else { sLog->outErrorDb("Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have target TARGET_DEST_DB (17).", Spell_ID, effIndex); continue; } } while (result->NextRow()); /* // Check all spells for (uint32 i = 1; i < GetSpellInfoStoreSize; ++i) { SpellInfo const* spellInfo = GetSpellInfo(i); if (!spellInfo) continue; bool found = false; for (int j = 0; j < MAX_SPELL_EFFECTS; ++j) { switch (spellInfo->Effects[j].TargetA) { case TARGET_DEST_DB: found = true; break; } if (found) break; switch (spellInfo->Effects[j].TargetB) { case TARGET_DEST_DB: found = true; break; } if (found) break; } if (found) { if (!sSpellMgr->GetSpellTargetPosition(i)) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell (ID: %u) does not have record in `spell_target_position`", i); #endif } }*/ sLog->outString(">> Loaded %u spell teleport coordinates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellGroups() { uint32 oldMSTime = getMSTime(); mSpellGroupMap.clear(); // need for reload case // 0 1 2 QueryResult result = WorldDatabase.Query("SELECT id, spell_id, special_flag FROM spell_group"); if (!result) { sLog->outString(">> Loaded 0 spell group definitions. DB table `spell_group` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 group_id = fields[0].GetUInt32(); int32 spell_id = fields[1].GetUInt32(); SpellGroupSpecialFlags specialFlag = (SpellGroupSpecialFlags)fields[2].GetUInt32(); SpellInfo const* spellInfo = GetSpellInfo(spell_id); if (!spellInfo) { sLog->outErrorDb("Spell %u listed in `spell_group` does not exist", spell_id); continue; } else if (spellInfo->GetRank() > 1) { sLog->outErrorDb("Spell %u listed in `spell_group` is not first rank of spell", spell_id); continue; } if (mSpellGroupMap.find(spell_id) != mSpellGroupMap.end()) { sLog->outErrorDb("Spell %u listed in `spell_group` has more than one group", spell_id); continue; } if (specialFlag >= SPELL_GROUP_SPECIAL_FLAG_MAX) { sLog->outErrorDb("Spell %u listed in `spell_group` has invalid special flag!", spell_id); continue; } SpellStackInfo ssi; ssi.groupId = group_id; ssi.specialFlags = specialFlag; mSpellGroupMap[spell_id] = ssi; ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u spell group definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellGroupStackRules() { uint32 oldMSTime = getMSTime(); mSpellGroupStackMap.clear(); // need for reload case // 0 1 QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules"); if (!result) { sLog->outString(">> Loaded 0 spell group stack rules. DB table `spell_group_stack_rules` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 group_id = fields[0].GetUInt32(); uint8 stack_rule = fields[1].GetInt8(); if (stack_rule >= SPELL_GROUP_STACK_FLAG_MAX) { sLog->outErrorDb("SpellGroupStackRule %u listed in `spell_group_stack_rules` does not exist", stack_rule); continue; } bool present = false; for (SpellGroupMap::const_iterator itr = mSpellGroupMap.begin(); itr != mSpellGroupMap.end(); ++itr) if (itr->second.groupId == group_id) { present = true; break; } if (!present) { sLog->outErrorDb("SpellGroup id %u listed in `spell_group_stack_rules` does not exist", group_id); continue; } mSpellGroupStackMap[group_id] = (SpellGroupStackFlags)stack_rule; ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u spell group stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellProcEvents() { uint32 oldMSTime = getMSTime(); mSpellProcEventMap.clear(); // need for reload case // 0 1 2 3 4 5 6 7 8 9 10 QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event"); if (!result) { sLog->outString(">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty."); return; } uint32 count = 0; do { Field* fields = result->Fetch(); int32 spellId = fields[0].GetInt32(); bool allRanks = false; if (spellId < 0) { allRanks = true; spellId = -spellId; } SpellInfo const* spellInfo = GetSpellInfo(spellId); if (!spellInfo) { sLog->outErrorDb("Spell %u listed in `spell_proc_event` does not exist", spellId); continue; } if (allRanks) { if (!spellInfo->IsRanked()) sLog->outErrorDb("Spell %u listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId); if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId)) { sLog->outErrorDb("Spell %u listed in `spell_proc_event` is not first rank of spell.", spellId); continue; } } SpellProcEventEntry spellProcEvent; spellProcEvent.schoolMask = fields[1].GetInt8(); spellProcEvent.spellFamilyName = fields[2].GetUInt16(); spellProcEvent.spellFamilyMask[0] = fields[3].GetUInt32(); spellProcEvent.spellFamilyMask[1] = fields[4].GetUInt32(); spellProcEvent.spellFamilyMask[2] = fields[5].GetUInt32(); spellProcEvent.procFlags = fields[6].GetUInt32(); spellProcEvent.procEx = fields[7].GetUInt32(); spellProcEvent.ppmRate = fields[8].GetFloat(); spellProcEvent.customChance = fields[9].GetFloat(); spellProcEvent.cooldown = fields[10].GetUInt32(); while (spellInfo) { if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end()) { sLog->outErrorDb("Spell %u listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id); break; } if (!spellInfo->ProcFlags && !spellProcEvent.procFlags) sLog->outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell", spellInfo->Id); mSpellProcEventMap[spellInfo->Id] = spellProcEvent; if (allRanks) spellInfo = spellInfo->GetNextRankSpell(); else break; } ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u extra spell proc event conditions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } void SpellMgr::LoadSpellProcs() { uint32 oldMSTime = getMSTime(); mSpellProcMap.clear(); // need for reload case // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc"); if (!result) { sLog->outString(">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); int32 spellId = fields[0].GetInt32(); bool allRanks = false; if (spellId < 0) { allRanks = true; spellId = -spellId; } SpellInfo const* spellInfo = GetSpellInfo(spellId); if (!spellInfo) { sLog->outErrorDb("Spell %u listed in `spell_proc` does not exist", spellId); continue; } if (allRanks) { if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId)) { sLog->outErrorDb("Spell %u listed in `spell_proc` is not first rank of spell.", fields[0].GetInt32()); continue; } } SpellProcEntry baseProcEntry; baseProcEntry.schoolMask = fields[1].GetInt8(); baseProcEntry.spellFamilyName = fields[2].GetUInt16(); baseProcEntry.spellFamilyMask[0] = fields[3].GetUInt32(); baseProcEntry.spellFamilyMask[1] = fields[4].GetUInt32(); baseProcEntry.spellFamilyMask[2] = fields[5].GetUInt32(); baseProcEntry.typeMask = fields[6].GetUInt32(); baseProcEntry.spellTypeMask = fields[7].GetUInt32(); baseProcEntry.spellPhaseMask = fields[8].GetUInt32(); baseProcEntry.hitMask = fields[9].GetUInt32(); baseProcEntry.attributesMask = fields[10].GetUInt32(); baseProcEntry.ratePerMinute = fields[11].GetFloat(); baseProcEntry.chance = fields[12].GetFloat(); float cooldown = fields[13].GetFloat(); baseProcEntry.cooldown = uint32(cooldown); baseProcEntry.charges = fields[14].GetUInt32(); while (spellInfo) { if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end()) { sLog->outErrorDb("Spell %u listed in `spell_proc` has duplicate entry in the table", spellId); break; } SpellProcEntry procEntry = SpellProcEntry(baseProcEntry); // take defaults from dbcs if (!procEntry.typeMask) procEntry.typeMask = spellInfo->ProcFlags; if (!procEntry.charges) procEntry.charges = spellInfo->ProcCharges; if (!procEntry.chance && !procEntry.ratePerMinute) procEntry.chance = float(spellInfo->ProcChance); // validate data if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL) sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `schoolMask` set: %u", spellId, procEntry.schoolMask); if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16)) sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `spellFamilyName` set: %u", spellId, procEntry.spellFamilyName); if (procEntry.chance < 0) { sLog->outErrorDb("`spell_proc` table entry for spellId %u has negative value in `chance` field", spellId); procEntry.chance = 0; } if (procEntry.ratePerMinute < 0) { sLog->outErrorDb("`spell_proc` table entry for spellId %u has negative value in `ratePerMinute` field", spellId); procEntry.ratePerMinute = 0; } if (cooldown < 0) { sLog->outErrorDb("`spell_proc` table entry for spellId %u has negative value in `cooldown` field", spellId); procEntry.cooldown = 0; } if (procEntry.chance == 0 && procEntry.ratePerMinute == 0) sLog->outErrorDb("`spell_proc` table entry for spellId %u doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellId); if (procEntry.charges > 99) { sLog->outErrorDb("`spell_proc` table entry for spellId %u has too big value in `charges` field", spellId); procEntry.charges = 99; } if (!procEntry.typeMask) sLog->outErrorDb("`spell_proc` table entry for spellId %u doesn't have `typeMask` value defined, proc will not be triggered", spellId); if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL) sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `spellTypeMask` set: %u", spellId, procEntry.spellTypeMask); if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))) sLog->outErrorDb("`spell_proc` table entry for spellId %u has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellId); if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK) sLog->outErrorDb("`spell_proc` table entry for spellId %u doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId); if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `spellPhaseMask` set: %u", spellId, procEntry.spellPhaseMask); if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)) sLog->outErrorDb("`spell_proc` table entry for spellId %u has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellId); if (procEntry.hitMask & ~PROC_HIT_MASK_ALL) sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `hitMask` set: %u", spellId, procEntry.hitMask); if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) sLog->outErrorDb("`spell_proc` table entry for spellId %u has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellId); mSpellProcMap[spellInfo->Id] = procEntry; if (allRanks) spellInfo = spellInfo->GetNextRankSpell(); else break; } ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellBonusess() { uint32 oldMSTime = getMSTime(); mSpellBonusMap.clear(); // need for reload case // 0 1 2 3 4 QueryResult result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data"); if (!result) { sLog->outString(">> Loaded 0 spell bonus data. DB table `spell_bonus_data` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); SpellInfo const* spell = GetSpellInfo(entry); if (!spell) { sLog->outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry); continue; } SpellBonusEntry& sbe = mSpellBonusMap[entry]; sbe.direct_damage = fields[1].GetFloat(); sbe.dot_damage = fields[2].GetFloat(); sbe.ap_bonus = fields[3].GetFloat(); sbe.ap_dot_bonus = fields[4].GetFloat(); ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u extra spell bonus data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellThreats() { uint32 oldMSTime = getMSTime(); mSpellThreatMap.clear(); // need for reload case // 0 1 2 3 QueryResult result = WorldDatabase.Query("SELECT entry, flatMod, pctMod, apPctMod FROM spell_threat"); if (!result) { sLog->outString(">> Loaded 0 aggro generating spells. DB table `spell_threat` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); if (!GetSpellInfo(entry)) { sLog->outErrorDb("Spell %u listed in `spell_threat` does not exist", entry); continue; } SpellThreatEntry ste; ste.flatMod = fields[1].GetInt32(); ste.pctMod = fields[2].GetFloat(); ste.apPctMod = fields[3].GetFloat(); mSpellThreatMap[entry] = ste; ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u SpellThreatEntries in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellMixology() { uint32 oldMSTime = getMSTime(); mSpellMixologyMap.clear(); // need for reload case // 0 1 QueryResult result = WorldDatabase.Query("SELECT entry, pctMod FROM spell_mixology"); if (!result) { sLog->outString(">> Loaded 0 mixology bonuses. DB table `spell_mixology` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); if (!GetSpellInfo(entry)) { sLog->outErrorDb("Spell %u listed in `spell_mixology` does not exist", entry); continue; } mSpellMixologyMap[entry] = fields[1].GetFloat();; ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u Mixology bonuses in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSkillLineAbilityMap() { uint32 oldMSTime = getMSTime(); mSkillLineAbilityMap.clear(); uint32 count = 0; for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); ++i) { SkillLineAbilityEntry const* SkillInfo = sSkillLineAbilityStore.LookupEntry(i); if (!SkillInfo) continue; mSkillLineAbilityMap.insert(SkillLineAbilityMap::value_type(SkillInfo->spellId, SkillInfo)); ++count; } sLog->outString(">> Loaded %u SkillLineAbility MultiMap Data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellPetAuras() { uint32 oldMSTime = getMSTime(); mSpellPetAuraMap.clear(); // need for reload case // 0 1 2 3 QueryResult result = WorldDatabase.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras"); if (!result) { sLog->outString(">> Loaded 0 spell pet auras. DB table `spell_pet_auras` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 spell = fields[0].GetUInt32(); uint8 eff = fields[1].GetUInt8(); uint32 pet = fields[2].GetUInt32(); uint32 aura = fields[3].GetUInt32(); SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find((spell << 8) + eff); if (itr != mSpellPetAuraMap.end()) itr->second.AddAura(pet, aura); else { SpellInfo const* spellInfo = GetSpellInfo(spell); if (!spellInfo) { sLog->outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell); continue; } if (spellInfo->Effects[eff].Effect != SPELL_EFFECT_DUMMY && (spellInfo->Effects[eff].Effect != SPELL_EFFECT_APPLY_AURA || spellInfo->Effects[eff].ApplyAuraName != SPELL_AURA_DUMMY)) { sLog->outError("Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell); continue; } SpellInfo const* spellInfo2 = GetSpellInfo(aura); if (!spellInfo2) { sLog->outErrorDb("Aura %u listed in `spell_pet_auras` does not exist", aura); continue; } PetAura pa(pet, aura, spellInfo->Effects[eff].TargetA.GetTarget() == TARGET_UNIT_PET, spellInfo->Effects[eff].CalcValue()); mSpellPetAuraMap[(spell << 8) + eff] = pa; } ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u spell pet auras in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } // Fill custom data about enchancments void SpellMgr::LoadEnchantCustomAttr() { uint32 oldMSTime = getMSTime(); uint32 size = sSpellItemEnchantmentStore.GetNumRows(); mEnchantCustomAttr.resize(size); for (uint32 i = 0; i < size; ++i) mEnchantCustomAttr[i] = 0; uint32 count = 0; for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo const* spellInfo = GetSpellInfo(i); if (!spellInfo) continue; // TODO: find a better check // Xinef: commented second part, fixes warlock enchants like firestone, spellstone if (!spellInfo->HasAttribute(SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA)/* || !spellInfo->HasAttribute(SPELL_ATTR0_NOT_SHAPESHIFT)*/) continue; for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) { if (spellInfo->Effects[j].Effect == SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) { uint32 enchId = spellInfo->Effects[j].MiscValue; SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchId); if (!ench) continue; mEnchantCustomAttr[enchId] = true; ++count; break; } } } sLog->outString(">> Loaded %u custom enchant attributes in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellEnchantProcData() { uint32 oldMSTime = getMSTime(); mSpellEnchantProcEventMap.clear(); // need for reload case // 0 1 2 3 QueryResult result = WorldDatabase.Query("SELECT entry, customChance, PPMChance, procEx FROM spell_enchant_proc_data"); if (!result) { sLog->outString(">> Loaded 0 spell enchant proc event conditions. DB table `spell_enchant_proc_data` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 enchantId = fields[0].GetUInt32(); SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchantId); if (!ench) { sLog->outErrorDb("Enchancment %u listed in `spell_enchant_proc_data` does not exist", enchantId); continue; } SpellEnchantProcEntry spe; spe.customChance = fields[1].GetUInt32(); spe.PPMChance = fields[2].GetFloat(); spe.procEx = fields[3].GetUInt32(); mSpellEnchantProcEventMap[enchantId] = spe; ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u enchant proc data definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellLinked() { uint32 oldMSTime = getMSTime(); mSpellLinkedMap.clear(); // need for reload case // 0 1 2 QueryResult result = WorldDatabase.Query("SELECT spell_trigger, spell_effect, type FROM spell_linked_spell"); if (!result) { sLog->outString(">> Loaded 0 linked spells. DB table `spell_linked_spell` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); int32 trigger = fields[0].GetInt32(); int32 effect = fields[1].GetInt32(); int32 type = fields[2].GetUInt8(); SpellInfo const* spellInfo = GetSpellInfo(abs(trigger)); if (!spellInfo) { sLog->outErrorDb("Spell %u listed in `spell_linked_spell` does not exist", abs(trigger)); continue; } spellInfo = GetSpellInfo(abs(effect)); if (!spellInfo) { sLog->outErrorDb("Spell %u listed in `spell_linked_spell` does not exist", abs(effect)); continue; } if (type) //we will find a better way when more types are needed { if (trigger > 0) trigger += SPELL_LINKED_MAX_SPELLS * type; else trigger -= SPELL_LINKED_MAX_SPELLS * type; } mSpellLinkedMap[trigger].push_back(effect); ++count; } while (result->NextRow()); sLog->outString(">> Loaded %u linked spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadPetLevelupSpellMap() { uint32 oldMSTime = getMSTime(); mPetLevelupSpellMap.clear(); // need for reload case uint32 count = 0; uint32 family_count = 0; for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i) { CreatureFamilyEntry const* creatureFamily = sCreatureFamilyStore.LookupEntry(i); if (!creatureFamily) // not exist continue; for (uint8 j = 0; j < 2; ++j) { if (!creatureFamily->skillLine[j]) continue; for (uint32 k = 0; k < sSkillLineAbilityStore.GetNumRows(); ++k) { SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(k); if (!skillLine) continue; //if (skillLine->skillId != creatureFamily->skillLine[0] && // (!creatureFamily->skillLine[1] || skillLine->skillId != creatureFamily->skillLine[1])) // continue; if (skillLine->skillId != creatureFamily->skillLine[j]) continue; if (skillLine->learnOnGetSkill != ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL) continue; SpellInfo const* spell = GetSpellInfo(skillLine->spellId); if (!spell) // not exist or triggered or talent continue; if (!spell->SpellLevel) continue; PetLevelupSpellSet& spellSet = mPetLevelupSpellMap[creatureFamily->ID]; if (spellSet.empty()) ++family_count; spellSet.insert(PetLevelupSpellSet::value_type(spell->SpellLevel, spell->Id)); ++count; } } } sLog->outString(">> Loaded %u pet levelup and default spells for %u families in %u ms", count, family_count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } bool LoadPetDefaultSpells_helper(CreatureTemplate const* cInfo, PetDefaultSpellsEntry& petDefSpells) { // skip empty list; bool have_spell = false; for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j) { if (petDefSpells.spellid[j]) { have_spell = true; break; } } if (!have_spell) return false; // remove duplicates with levelupSpells if any if (PetLevelupSpellSet const* levelupSpells = cInfo->family ? sSpellMgr->GetPetLevelupSpellList(cInfo->family) : nullptr) { for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j) { if (!petDefSpells.spellid[j]) continue; for (PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr) { if (itr->second == petDefSpells.spellid[j]) { petDefSpells.spellid[j] = 0; break; } } } } // skip empty list; have_spell = false; for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j) { if (petDefSpells.spellid[j]) { have_spell = true; break; } } return have_spell; } void SpellMgr::LoadPetDefaultSpells() { uint32 oldMSTime = getMSTime(); mPetDefaultSpellsMap.clear(); uint32 countCreature = 0; uint32 countData = 0; CreatureTemplateContainer const* ctc = sObjectMgr->GetCreatureTemplates(); for (CreatureTemplateContainer::const_iterator itr = ctc->begin(); itr != ctc->end(); ++itr) { if (!itr->second.PetSpellDataId) continue; // for creature with PetSpellDataId get default pet spells from dbc CreatureSpellDataEntry const* spellDataEntry = sCreatureSpellDataStore.LookupEntry(itr->second.PetSpellDataId); if (!spellDataEntry) continue; int32 petSpellsId = -int32(itr->second.PetSpellDataId); PetDefaultSpellsEntry petDefSpells; for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j) petDefSpells.spellid[j] = spellDataEntry->spellId[j]; if (LoadPetDefaultSpells_helper(&itr->second, petDefSpells)) { mPetDefaultSpellsMap[petSpellsId] = petDefSpells; ++countData; } } sLog->outString(">> Loaded addition spells for %u pet spell data entries in %u ms", countData, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); sLog->outString("Loading summonable creature templates..."); oldMSTime = getMSTime(); // different summon spells for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo const* spellEntry = GetSpellInfo(i); if (!spellEntry) continue; for (uint8 k = 0; k < MAX_SPELL_EFFECTS; ++k) { if (spellEntry->Effects[k].Effect == SPELL_EFFECT_SUMMON || spellEntry->Effects[k].Effect == SPELL_EFFECT_SUMMON_PET) { uint32 creature_id = spellEntry->Effects[k].MiscValue; CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature_id); if (!cInfo) continue; // already loaded if (cInfo->PetSpellDataId) continue; // for creature without PetSpellDataId get default pet spells from creature_template int32 petSpellsId = cInfo->Entry; if (mPetDefaultSpellsMap.find(cInfo->Entry) != mPetDefaultSpellsMap.end()) continue; PetDefaultSpellsEntry petDefSpells; for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j) petDefSpells.spellid[j] = cInfo->spells[j]; if (LoadPetDefaultSpells_helper(cInfo, petDefSpells)) { mPetDefaultSpellsMap[petSpellsId] = petDefSpells; ++countCreature; } } } } sLog->outString(">> Loaded %u summonable creature templates in %u ms", countCreature, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellAreas() { uint32 oldMSTime = getMSTime(); mSpellAreaMap.clear(); // need for reload case mSpellAreaForQuestMap.clear(); mSpellAreaForQuestEndMap.clear(); mSpellAreaForAuraMap.clear(); // 0 1 2 3 4 5 6 7 8 9 QueryResult result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_status, quest_end_status, quest_end, aura_spell, racemask, gender, autocast FROM spell_area"); if (!result) { sLog->outString(">> Loaded 0 spell area requirements. DB table `spell_area` is empty."); sLog->outString(); return; } uint32 count = 0; do { Field* fields = result->Fetch(); uint32 spell = fields[0].GetUInt32(); SpellArea spellArea; spellArea.spellId = spell; spellArea.areaId = fields[1].GetUInt32(); spellArea.questStart = fields[2].GetUInt32(); spellArea.questStartStatus = fields[3].GetUInt32(); spellArea.questEndStatus = fields[4].GetUInt32(); spellArea.questEnd = fields[5].GetUInt32(); spellArea.auraSpell = fields[6].GetInt32(); spellArea.raceMask = fields[7].GetUInt32(); spellArea.gender = Gender(fields[8].GetUInt8()); spellArea.autocast = fields[9].GetBool(); if (SpellInfo const* spellInfo = GetSpellInfo(spell)) { if (spellArea.autocast) const_cast(spellInfo)->Attributes |= SPELL_ATTR0_CANT_CANCEL; } else { sLog->outErrorDb("Spell %u listed in `spell_area` does not exist", spell); continue; } { bool ok = true; SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId); for (SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr) { if (spellArea.spellId != itr->second.spellId) continue; if (spellArea.areaId != itr->second.areaId) continue; if (spellArea.questStart != itr->second.questStart) continue; if (spellArea.auraSpell != itr->second.auraSpell) continue; if ((spellArea.raceMask & itr->second.raceMask) == 0) continue; if (spellArea.gender != itr->second.gender) continue; // duplicate by requirements ok = false; break; } if (!ok) { sLog->outErrorDb("Spell %u listed in `spell_area` already listed with similar requirements.", spell); continue; } } if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId)) { sLog->outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId); continue; } if (spellArea.questStart && !sObjectMgr->GetQuestTemplate(spellArea.questStart)) { sLog->outErrorDb("Spell %u listed in `spell_area` have wrong start quest (%u) requirement", spell, spellArea.questStart); continue; } if (spellArea.questEnd) { if (!sObjectMgr->GetQuestTemplate(spellArea.questEnd)) { sLog->outErrorDb("Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell, spellArea.questEnd); continue; } } if (spellArea.auraSpell) { SpellInfo const* spellInfo = GetSpellInfo(abs(spellArea.auraSpell)); if (!spellInfo) { sLog->outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell, abs(spellArea.auraSpell)); continue; } if (uint32(abs(spellArea.auraSpell)) == spellArea.spellId) { sLog->outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell, abs(spellArea.auraSpell)); continue; } // not allow autocast chains by auraSpell field (but allow use as alternative if not present) if (spellArea.autocast && spellArea.auraSpell > 0) { bool chain = false; SpellAreaForAuraMapBounds saBound = GetSpellAreaForAuraMapBounds(spellArea.spellId); for (SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr) { if (itr->second->autocast && itr->second->auraSpell > 0) { chain = true; break; } } if (chain) { sLog->outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell, spellArea.auraSpell); continue; } SpellAreaMapBounds saBound2 = GetSpellAreaMapBounds(spellArea.auraSpell); for (SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2) { if (itr2->second.autocast && itr2->second.auraSpell > 0) { chain = true; break; } } if (chain) { sLog->outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell, spellArea.auraSpell); continue; } } } if (spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE) == 0) { sLog->outErrorDb("Spell %u listed in `spell_area` have wrong race mask (%u) requirement", spell, spellArea.raceMask); continue; } if (spellArea.gender != GENDER_NONE && spellArea.gender != GENDER_FEMALE && spellArea.gender != GENDER_MALE) { sLog->outErrorDb("Spell %u listed in `spell_area` have wrong gender (%u) requirement", spell, spellArea.gender); continue; } SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell, spellArea))->second; // for search by current zone/subzone at zone/subzone change if (spellArea.areaId) mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId, sa)); // for search at quest start/reward if (spellArea.questStart) mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa)); // for search at quest start/reward if (spellArea.questEnd) mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa)); // for search at aura apply if (spellArea.auraSpell) mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell), sa)); ++count; } while (result->NextRow()); if (sWorld->getIntConfig(CONFIG_ICC_BUFF_HORDE) > 0) { sLog->outString(">> Using ICC buff Horde: %u", sWorld->getIntConfig(CONFIG_ICC_BUFF_HORDE)); SpellArea spellAreaICCBuffHorde = { sWorld->getIntConfig(CONFIG_ICC_BUFF_HORDE), ICC_AREA, 0, 0, 0, ICC_RACEMASK_HORDE, Gender(2), 64, 11, 1 }; SpellArea const* saICCBuffHorde = &mSpellAreaMap.insert(SpellAreaMap::value_type(sWorld->getIntConfig(CONFIG_ICC_BUFF_HORDE), spellAreaICCBuffHorde))->second; mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(ICC_AREA, saICCBuffHorde)); ++count; } else sLog->outString(">> ICC buff Horde: disabled"); if (sWorld->getIntConfig(CONFIG_ICC_BUFF_ALLIANCE) > 0) { sLog->outString(">> Using ICC buff Alliance: %u", sWorld->getIntConfig(CONFIG_ICC_BUFF_ALLIANCE)); SpellArea spellAreaICCBuffAlliance = { sWorld->getIntConfig(CONFIG_ICC_BUFF_ALLIANCE), ICC_AREA, 0, 0, 0, ICC_RACEMASK_ALLIANCE, Gender(2), 64, 11, 1 }; SpellArea const* saICCBuffAlliance = &mSpellAreaMap.insert(SpellAreaMap::value_type(sWorld->getIntConfig(CONFIG_ICC_BUFF_ALLIANCE), spellAreaICCBuffAlliance))->second; mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(ICC_AREA, saICCBuffAlliance)); ++count; } else sLog->outString(">> ICC buff Alliance: disabled"); sLog->outString(">> Loaded %u spell area requirements in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellInfoStore() { uint32 oldMSTime = getMSTime(); UnloadSpellInfoStore(); mSpellInfoMap.resize(sSpellStore.GetNumRows(), nullptr); for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) { if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(i)) mSpellInfoMap[i] = new SpellInfo(spellEntry); } sLog->outString(">> Loaded spell custom attributes in %u ms", GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::UnloadSpellInfoStore() { for (uint32 i = 0; i < mSpellInfoMap.size(); ++i) { if (mSpellInfoMap[i]) delete mSpellInfoMap[i]; } mSpellInfoMap.clear(); } void SpellMgr::UnloadSpellInfoImplicitTargetConditionLists() { for (uint32 i = 0; i < mSpellInfoMap.size(); ++i) { if (mSpellInfoMap[i]) mSpellInfoMap[i]->_UnloadImplicitTargetConditionLists(); } } void SpellMgr::LoadSpellSpecificAndAuraState() { uint32 oldMSTime = getMSTime(); SpellInfo* spellInfo = nullptr; for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { spellInfo = mSpellInfoMap[i]; if (!spellInfo) continue; spellInfo->_spellSpecific = spellInfo->LoadSpellSpecific(); spellInfo->_auraState = spellInfo->LoadAuraState(); } sLog->outString(">> Loaded spell specific and aura state in %u ms", GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } void SpellMgr::LoadSpellCustomAttr() { uint32 oldMSTime = getMSTime(); uint32 customAttrTime = getMSTime(); uint32 count; QueryResult result = WorldDatabase.Query("SELECT spell_id, attributes FROM spell_custom_attr"); if (!result) sLog->outString(">> Loaded 0 spell custom attributes from DB. DB table `spell_custom_attr` is empty."); else { for (count = 0; result->NextRow(); ++count) { Field* fields = result->Fetch(); uint32 spellId = fields[0].GetUInt32(); uint32 attributes = fields[1].GetUInt32(); SpellInfo* spellInfo = _GetSpellInfo(spellId); if (!spellInfo) { sLog->outString("Table `spell_custom_attr` has wrong spell (spell_id: %u), ignored.", spellId); continue; } if ((attributes & SPELL_ATTR0_CU_NEGATIVE) != 0) { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (spellInfo->Effects[i].IsEffect()) continue; if ((attributes & (SPELL_ATTR0_CU_NEGATIVE_EFF0 << i)) != 0) { sLog->outErrorDb("Table `spell_custom_attr` has attribute SPELL_ATTR0_CU_NEGATIVE_EFF%u for spell %u with no EFFECT_%u", uint32(i), spellId, uint32(i)); continue; } } } if ((attributes & SPELL_ATTR0_CU_POSITIVE) != 0) { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (spellInfo->Effects[i].IsEffect()) continue; if ((attributes & (SPELL_ATTR0_CU_POSITIVE_EFF0 << i)) != 0) { sLog->outErrorDb("Table `spell_custom_attr` has attribute SPELL_ATTR0_CU_POSITIVE_EFF%u for spell %u with no EFFECT_%u", uint32(i), spellId, uint32(i)); continue; } } } spellInfo->AttributesCu |= attributes; } sLog->outString(">> Loaded %u spell custom attributes from DB in %u ms", count, GetMSTimeDiffToNow(customAttrTime)); } // xinef: create talent spells set for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) { TalentEntry const* talentInfo = sTalentStore.LookupEntry(i); if (!talentInfo) continue; for (uint8 j = 0; j < MAX_TALENT_RANK; j++) if (uint32 spellId = talentInfo->RankID[j]) if (const SpellInfo* spellInfo = GetSpellInfo(spellId)) for (uint8 k = 0; k < MAX_SPELL_EFFECTS; ++k) if (spellInfo->Effects[k].Effect == SPELL_EFFECT_LEARN_SPELL) if (const SpellInfo* learnSpell = GetSpellInfo(spellInfo->Effects[k].TriggerSpell)) if (learnSpell->IsRanked() && !learnSpell->HasAttribute(SpellAttr0(SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE))) mTalentSpellAdditionalSet.insert(learnSpell->Id); } SpellInfo* spellInfo = nullptr; for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { spellInfo = mSpellInfoMap[i]; if (!spellInfo) continue; for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) { switch (spellInfo->Effects[j].ApplyAuraName) { case SPELL_AURA_PERIODIC_HEAL: case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: case SPELL_AURA_PERIODIC_LEECH: case SPELL_AURA_PERIODIC_MANA_LEECH: case SPELL_AURA_PERIODIC_HEALTH_FUNNEL: case SPELL_AURA_PERIODIC_ENERGIZE: 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; break; } switch (spellInfo->Effects[j].Effect) { case SPELL_EFFECT_SCHOOL_DAMAGE: 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_HEAL: spellInfo->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE; break; case SPELL_EFFECT_POWER_DRAIN: case SPELL_EFFECT_POWER_BURN: case SPELL_EFFECT_HEAL_MAX_HEALTH: case SPELL_EFFECT_HEALTH_LEECH: case SPELL_EFFECT_HEAL_PCT: case SPELL_EFFECT_ENERGIZE_PCT: case SPELL_EFFECT_ENERGIZE: case SPELL_EFFECT_HEAL_MECHANICAL: spellInfo->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; break; case SPELL_EFFECT_PICKPOCKET: spellInfo->AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET; break; case SPELL_EFFECT_ENCHANT_ITEM: case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY: case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC: case SPELL_EFFECT_ENCHANT_HELD_ITEM: { // only enchanting profession enchantments procs can stack if (IsPartOfSkillLine(SKILL_ENCHANTING, i)) { uint32 enchantId = spellInfo->Effects[j].MiscValue; SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId); for (uint8 s = 0; s < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++s) { if (enchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) continue; SpellInfo* procInfo = (SpellInfo*)GetSpellInfo(enchant->spellid[s]); if (!procInfo) 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(SPELL_AURA_PROC_TRIGGER_SPELL)) continue; procInfo->AttributesCu |= SPELL_ATTR0_CU_ENCHANT_PROC; } } break; } } } // Xinef: spells ignoring hit result should not be binary if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT)) { for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) { if (spellInfo->Effects[j].Effect) { switch(spellInfo->Effects[j].Effect) { case SPELL_EFFECT_SCHOOL_DAMAGE: 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_TRIGGER_SPELL: case SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE: continue; case SPELL_EFFECT_PERSISTENT_AREA_AURA: case SPELL_EFFECT_APPLY_AURA: case SPELL_EFFECT_APPLY_AREA_AURA_PARTY: case SPELL_EFFECT_APPLY_AREA_AURA_RAID: case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: case SPELL_EFFECT_APPLY_AREA_AURA_PET: case SPELL_EFFECT_APPLY_AREA_AURA_OWNER: if (spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE || spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE_PERCENT || spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_DUMMY || spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_LEECH || spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_HEALTH_FUNNEL || spellInfo->Effects[j].ApplyAuraName == SPELL_AURA_PERIODIC_DUMMY) continue; [[fallthrough]]; // TODO: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked. default: if (spellInfo->Effects[j].CalcValue() || ((spellInfo->Effects[j].Effect == SPELL_EFFECT_INTERRUPT_CAST || spellInfo->HasAttribute(SPELL_ATTR0_CU_DONT_BREAK_STEALTH)) && !spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))) 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) // Sindragosa Frost Breath if (spellInfo->SpellFamilyName != SPELLFAMILY_MAGE || !(spellInfo->SpellFamilyFlags[0] & 0x20)) // frostbolt if (spellInfo->Id != 55095) // frost fever if (spellInfo->SpellFamilyName != SPELLFAMILY_WARLOCK || !(spellInfo->SpellFamilyFlags[1] & 0x40000)) // Haunt { spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY_SPELL; break; } continue; } } } } // pussywizard: if ((spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) && (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_MAGIC)) { spellInfo->SchoolMask &= ~SPELL_SCHOOL_MASK_NORMAL; spellInfo->AttributesCu |= SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC; } if (!spellInfo->_IsPositiveEffect(EFFECT_0, false)) spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0; if (!spellInfo->_IsPositiveEffect(EFFECT_1, false)) spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF1; if (!spellInfo->_IsPositiveEffect(EFFECT_2, false)) spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF2; if (spellInfo->SpellVisual[0] == 3879) spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK; switch (spellInfo->Id) { // Xinef: additional spells which should be binary case 45145: // Snake Trap Effect spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY_SPELL; break; case 1776: // Gouge case 1777: case 8629: case 11285: case 11286: case 12540: case 13579: case 24698: case 28456: case 29425: case 34940: case 36862: case 38764: case 38863: case 52743: // Head Smack spellInfo->AttributesCu |= SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER; break; case 53: // Backstab case 2589: case 2590: case 2591: case 7159: case 8627: case 8721: case 11279: case 11280: case 11281: case 15582: case 15657: case 22416: case 25300: case 26863: case 37685: case 48656: case 48657: case 703: // Garrote case 8631: case 8632: case 8633: case 11289: case 11290: case 26839: case 26884: case 48675: case 48676: case 5221: // Shred case 6800: case 8992: case 9829: case 9830: case 27001: case 27002: case 48571: case 48572: case 8676: // Ambush case 8724: case 8725: case 11267: case 11268: case 11269: case 27441: case 48689: case 48690: case 48691: case 6785: // Ravage case 6787: case 9866: case 9867: case 27005: case 48578: case 48579: case 21987: // Lash of Pain case 23959: // Test Stab R50 case 24825: // Test Backstab case 58563: // Assassinate Restless Lookout case 63124: // quest There's Something About the Squire (13654) spellInfo->AttributesCu |= SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET; break; case 26029: // Dark Glare case 43140: // Flame Breath case 43215: // Flame Breath case 70461: // Coldflame Trap case 72133: // Pain and Suffering case 73788: // Pain and Suffering case 73789: // Pain and Suffering case 73790: // Pain and Suffering case 63293: // Mimiron - spinning damage case 68873: // Wailing Souls case 70324: // Wailing Souls case 64619: // Ulduar, Mimiron, Emergency Fire Bot, Water Spray spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_LINE; break; case 58690: // Cyanigosa, Tail Sweep case 59283: // Cyanigosa, Tail Sweep spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK; break; case 24340: // Meteor case 26558: // Meteor case 28884: // Meteor case 36837: // Meteor case 38903: // Meteor case 41276: // Meteor case 57467: // Meteor case 26789: // Shard of the Fallen Star case 31436: // Malevolent Cleave case 35181: // Dive Bomb case 40810: // Saber Lash case 43267: // Saber Lash case 43268: // Saber Lash case 42384: // Brutal Swipe case 45150: // Meteor Slash case 64688: // Sonic Screech case 72373: // Shared Suffering case 71904: // Chaos Bane case 70492: // Ooze Eruption case 72505: // Ooze Eruption case 72624: // Ooze Eruption case 72625: // Ooze Eruption // ONLY SPELLS WITH SPELLFAMILY_GENERIC and EFFECT_SCHOOL_DAMAGE, OR WEAPON_DMG_X case 66809: // Meteor Fists case 67331: // Meteor Fists case 66765: // Meteor Fists case 67333: // Meteor Fists spellInfo->AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE; break; case 18500: // Wing Buffet case 33086: // Wild Bite case 49749: // Piercing Blow case 52890: // Penetrating Strike case 53454: // Impale case 59446: // Impale case 62383: // Shatter case 64777: // Machine Gun case 65239: // Machine Gun case 69293: // Wing Buffet case 74439: // Machine Gun // Trial of the Crusader, Jaraxxus, Shivan Slash case 66378: case 67097: case 67098: case 67099: // Trial of the Crusader, Anub'arak, Impale case 65919: case 67858: case 67859: case 67860: case 63278: // Mark of the Faceless (General Vezax) case 64125: // Ulduar, Yogg-Saron, Squeeze case 64126: // Ulduar, Yogg-Saron, Squeeze case 62544: // Thrust (Argent Tournament) case 64588: // Thrust (Argent Tournament) case 66479: // Thrust (Argent Tournament) case 68505: // Thrust (Argent Tournament) case 62709: // Counterattack! (Argent Tournament) case 62626: // Break-Shield (Argent Tournament, Player) case 64590: // Break-Shield (Argent Tournament, Player) case 64342: // Break-Shield (Argent Tournament, NPC) case 64686: // Break-Shield (Argent Tournament, NPC) case 65147: // Break-Shield (Argent Tournament, NPC) case 68504: // Break-Shield (Argent Tournament, NPC) case 62874: // Charge (Argent Tournament, Player) case 68498: // Charge (Argent Tournament, Player) case 64591: // Charge (Argent Tournament, Player) case 63003: // Charge (Argent Tournament, NPC) case 63010: // Charge (Argent Tournament, NPC) case 68321: // Charge (Argent Tournament, NPC) case 72255: // Mark of the Fallen Champion (Deathbringer Saurfang) case 72444: // Mark of the Fallen Champion (Deathbringer Saurfang) case 72445: // Mark of the Fallen Champion (Deathbringer Saurfang) case 72446: // Mark of the Fallen Champion (Deathbringer Saurfang) case 72409: // Rune of Blood (Deathbringer Saurfang) case 72447: // Rune of Blood (Deathbringer Saurfang) case 72448: // Rune of Blood (Deathbringer Saurfang) case 72449: // Rune of Blood (Deathbringer Saurfang) case 49882: // Leviroth Self-Impale case 62775: // Ulduar: XT-002 Tympanic Tamparum spellInfo->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR; break; case 64422: // Sonic Screech (Auriaya) case 13877: // Blade Flurry (Rogue Spell) should ignore armor and share damage to 2nd mob spellInfo->AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE; spellInfo->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR; break; case 72293: // Mark of the Fallen Champion (Deathbringer Saurfang) case 72347: // Lock Players and Tap Chest (Gunship Battle) spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0; break; default: break; case 63675: // Improved Devouring Plague case 17962: // Conflagrate case 32593: // Earth Shield aura case 32594: // Earth Shield aura case 49283: // Earth Shield aura case 49284: // Earth Shield aura case 50526: // Wandering Plague case 53353: // Chimera Shot - Serpent trigger case 52752: // Ancestral Awakening Heal spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_POSITIVE_TAKEN_BONUS; break; case 65280: // Ulduar, Hodir, Singed case 65775: // Anub'arak, Swarm Scarab, Acid-Drenched Mandibles (10 normal) case 67861: // Anub'arak, Swarm Scarab, Acid-Drenched Mandibles (25 normal) case 67862: // Anub'arak, Swarm Scarab, Acid-Drenched Mandibles (10 heroic) case 67863: // Anub'arak, Swarm Scarab, Acid-Drenched Mandibles (25 heroic) case 55604: // Naxxramas, Unrelenting Trainee, Death Plague (10 mode) case 55645: // Naxxramas, Unrelenting Trainee, Death Plague (25 mode) case 67721: // Anub'arak, Nerubian Burrower, Expose Weakness (normal) case 67847: // Anub'arak, Nerubian Burrower, Expose Weakness (heroic) case 64638: // Ulduar, Winter Jormungar, Acidic Bite case 71157: // Icecrown Citadel, Plagued Zombie, Infected Wound case 72963: // Icecrown Citadel, Rot Worm, Flesh Rot (10 normal) case 72964: // Icecrown Citadel, Rot Worm, Flesh Rot (25 normal) case 72965: // Icecrown Citadel, Rot Worm, Flesh Rot (10 heroic) case 72966: // Icecrown Citadel, Rot Worm, Flesh Rot (25 heroic) case 72465: // Icecrown Citadel, Sindragosa, Respite for a Tormented Soul (weekly quest) case 45271: // Sunwell, Eredar Twins encounter, Dark Strike case 45347: // Sunwell, Eredar Twins encounter, Dark Touched case 45348: // Sunwell, Eredar Twins encounter, Flame Touched case 35859: // The Eye, Nether Vapor case 40520: // Black Temple, Shade Soul Channel case 40327: // Black Temple, Atrophy case 38449: // Serpentshrine Cavern, Blessing of the Tides case 38044: // Serpentshrine Cavern, Surge case 74507: // Ruby Sanctum, Siphoned Might case 49381: // Drak'tharon Keep, Consume case 59805: // Drak'tharon Keep, Consume case 55093: // Gundrak, Grip of Slad'ran case 30659: // Hellfire Ramparts, Fel Infusion case 54314: // Azjol'Nerub Drain Power case 59354: // Azjol'Nerub Drain Power case 34655: // Snake Trap, Deadly Poison case 11971: // Sunder Armor case 58567: // Player Sunder Armor case 12579: // Player Winter's Chill case 29306: // Naxxramas(Gluth's Zombies): Infected Wound case 61920: // Ulduar(Spellbreaker): Supercharge case 63978: // Ulduar(Rubble): Stone Nova spellInfo->AttributesCu |= SPELL_ATTR0_CU_SINGLE_AURA_STACK; break; case 43138: // North Fleet Reservist Kill Credit spellInfo->AttributesCu |= SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET; break; // Xinef: NOT CUSTOM, cant add in DBC CORRECTION because i need to swap effects, too much work to do there // Envenom case 32645: case 32684: case 57992: case 57993: { SpellEffectInfo info = spellInfo->Effects[EFFECT_0]; spellInfo->Effects[EFFECT_0] = spellInfo->Effects[EFFECT_2]; spellInfo->Effects[EFFECT_2] = info; break; } // Xinef: Cooldown overwrites // Jotunheim Rapid-Fire Harpoon: Energy Reserve case 56585: spellInfo->RecoveryTime = 30000; spellInfo->_requireCooldownInfo = true; break; // Jotunheim Rapid-Fire Harpoon: Rapid-Fire Harpoon case 56570: spellInfo->RecoveryTime = 200; break; // Burst of Speed case 57493: spellInfo->RecoveryTime = 60000; spellInfo->_requireCooldownInfo = true; break; // Strafe Jotunheim Building case 7769: spellInfo->RecoveryTime = 1500; spellInfo->_requireCooldownInfo = true; break; case 44535: // Spirit Heal, abilities also have no cost spellInfo->Effects[EFFECT_0].MiscValue = 127; break; } } // Xinef: addition for binary spells, ommit spells triggering other spells for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { spellInfo = mSpellInfoMap[i]; if (!spellInfo) continue; if (!(spellInfo->AttributesCu & SPELL_ATTR0_CU_BINARY_SPELL)) continue; bool allNonBinary = true; bool overrideAttr = false; for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) { if (spellInfo->Effects[j].ApplyAuraName && spellInfo->Effects[j].TriggerSpell) { switch(spellInfo->Effects[j].ApplyAuraName) { case SPELL_AURA_PERIODIC_TRIGGER_SPELL: case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(spellInfo->Effects[j].TriggerSpell)) { overrideAttr = true; if (triggerSpell->AttributesCu & SPELL_ATTR0_CU_BINARY_SPELL) allNonBinary = false; } } } } if (overrideAttr && allNonBinary) spellInfo->AttributesCu &= ~SPELL_ATTR0_CU_BINARY_SPELL; } CreatureAI::FillAISpellInfo(); sLog->outString(">> Loaded spell custom attributes in %u ms", GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } inline void ApplySpellFix(std::initializer_list spellIds, void(*fix)(SpellEntry*)) { for (uint32 spellId : spellIds) { SpellEntry const* spellInfo = (SpellEntry*)sSpellStore.LookupEntry(spellId); if (!spellInfo) { sLog->outErrorDb("Spell info correction specified for non-existing spell %u", spellId); continue; } fix(const_cast(spellInfo)); } } void SpellMgr::LoadDbcDataCorrections() { uint32 oldMSTime = getMSTime(); ApplySpellFix({ 467, // Thorns (Rank 1) 782, // Thorns (Rank 2) 1075, // Thorns (Rank 3) 8914, // Thorns (Rank 4) 9756, // Thorns (Rank 5) 9910, // Thorns (Rank 6) 26992, // Thorns (Rank 7) 53307, // Thorns (Rank 8) 53352 // Explosive Shot (trigger) }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); // Elixir of Minor Fortitude ApplySpellFix({ 2378 }, [](SpellEntry* spellInfo) { spellInfo->manaCost = 0; spellInfo->manaPerSecond = 0; }); // Evergrove Druid Transform Crow ApplySpellFix({ 38776 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 4; // 120 seconds }); ApplySpellFix({ 63026, // Force Cast (HACK: Target shouldn't be changed) 63137 // Force Cast (HACK: Target shouldn't be changed; summon position should be untied from spell destination) }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_DEST_DB; }); ApplySpellFix({ 53096, // Quetz'lun's Judgment 70743, // AoD Special 70614 // AoD Special - Vegard }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; }); ApplySpellFix({ 52611, // Summon Skeletons 52612 // Summon Skeletons }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValueB[0] = 64; }); ApplySpellFix({ 45257, // Using Steam Tonk Controller 45440, // Steam Tonk Controller 60256, // Collect Sample 45634 // Neural Needle }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx4 &= ~SPELL_ATTR4_CAN_CAST_WHILE_CASTING; // Crashes client on pressing ESC }); ApplySpellFix({ 40244, // Simon Game Visual 40245, // Simon Game Visual 40246, // Simon Game Visual 40247, // Simon Game Visual 42835 // Spout, remove damage effect, only anim is needed }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; }); ApplySpellFix({ 63665, // Charge (Argent Tournament emote on riders) 31298, // Sleep (needs target selection script) 2895, // Wrath of Air Totem rank 1 (Aura) 68933, // Wrath of Air Totem rank 2 (Aura) 29200 // Purify Helboar Meat }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; spellInfo->EffectImplicitTargetB[0] = 0; }); // Howl of Azgalor ApplySpellFix({ 31344 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yards instead of 50000?! }); ApplySpellFix({ 42818, // Headless Horseman - Wisp Flight Port 42821 // Headless Horseman - Wisp Flight Missile }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 6; // 100 yards }); //They Must Burn Bomb Aura (self) ApplySpellFix({ 36350 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[0] = 36325; // They Must Burn Bomb Drop (DND) }); // Mana Shield (rank 2) ApplySpellFix({ 8494 }, [](SpellEntry* spellInfo) { spellInfo->procChance = 0; // because of bug in dbc }); ApplySpellFix({ 63320, // Glyph of Life Tap 20335, // Heart of the Crusader 20336, // Heart of the Crusader 20337, // Heart of the Crusader 53228, // Rapid Killing (Rank 1) 53232, // Rapid Killing (Rank 2) }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED; // Entries were not updated after spell effect change, we have to do that manually }); ApplySpellFix({ 31347, // Doom 41635, // Prayer of Mending 39365, // Thundering Storm 52124, // Sky Darkener Assault 42442, // Vengeance Landing Cannonfire 45863, // Cosmetic - Incinerate to Random Target 25425, // Shoot 45761, // Shoot 42611, // Shoot 61588, // Blazing Harpoon 36327 // Shoot Arcane Explosion Arrow }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; }); // Skartax Purple Beam ApplySpellFix({ 36384 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 2; }); ApplySpellFix({ 37790, // Spread Shot 54172, // Divine Storm (heal) 66588, // Flaming Spear 54171 // Divine Storm }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 3; }); // Divine Storm (Damage) ApplySpellFix({ 53385 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 4; }); // Spitfire Totem ApplySpellFix({ 38296 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 5; }); ApplySpellFix({ 40827, // Sinful Beam 40859, // Sinister Beam 40860, // Vile Beam 40861 // Wicked Beam }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 10; }); // Unholy Frenzy ApplySpellFix({ 50312 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 15; }); ApplySpellFix({ 17941, // Shadow Trance 22008, // Netherwind Focus 31834, // Light's Grace 34754, // Clearcasting 34936, // Backlash 48108, // Hot Streak 51124, // Killing Machine 54741, // Firestarter 57761, // Fireball! 64823, // Item - Druid T8 Balance 4P Bonus 34477, // Misdirection 44401, // Missile Barrage 18820 // Insight }, [](SpellEntry* spellInfo) { spellInfo->procCharges = 1; }); // Tidal Wave ApplySpellFix({ 53390 }, [](SpellEntry* spellInfo) { spellInfo->procCharges = 2; }); // Oscillation Field ApplySpellFix({ 37408 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Ascendance (Talisman of Ascendance trinket) ApplySpellFix({ 28200 }, [](SpellEntry* spellInfo) { spellInfo->procCharges = 6; }); // The Eye of Acherus (no spawn in phase 2 in db) ApplySpellFix({ 51852 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValue[0] |= 1; }); // Crafty's Ultra-Advanced Proto-Typical Shortening Blaster ApplySpellFix({ 51912 }, [](SpellEntry* spellInfo) { spellInfo->EffectAmplitude[0] = 3000; }); // Desecration Arm - 36 instead of 37 - typo? ApplySpellFix({ 29809 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 37; }); // Sic'em ApplySpellFix({ 42767 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_NEARBY_ENTRY; }); // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data // To prevent aura staying on target after talent unlearned ApplySpellFix({ 48420 }, [](SpellEntry* spellInfo) { spellInfo->Stances = 1 << (FORM_CAT - 1); }); ApplySpellFix({ 48421 }, [](SpellEntry* spellInfo) { spellInfo->Stances = 1 << (FORM_MOONKIN - 1); }); ApplySpellFix({ 48422 }, [](SpellEntry* spellInfo) { spellInfo->Stances = 1 << (FORM_TREE - 1); }); // Elemental Oath ApplySpellFix({ 51466, 51470 }, [](SpellEntry* spellInfo) { spellInfo->Effect[EFFECT_1] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[EFFECT_1] = SPELL_AURA_ADD_FLAT_MODIFIER; spellInfo->EffectMiscValue[EFFECT_1] = SPELLMOD_EFFECT2; spellInfo->EffectSpellClassMask[EFFECT_1] = flag96(0x00000000, 0x00004000, 0x00000000); }); // Improved Shadowform (Rank 1) ApplySpellFix({ 47569 }, [](SpellEntry* spellInfo) { spellInfo->Attributes &= ~SPELL_ATTR0_NOT_SHAPESHIFT; // with this spell atrribute aura can be stacked several times }); // Nether Portal - Perseverence ApplySpellFix({ 30421 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[2] += 30000; }); // Natural shapeshifter ApplySpellFix({ 16834, 16835 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 21; }); // Ebon Plague ApplySpellFix({ 51735, 51734, 51726 }, [](SpellEntry* spellInfo) { spellInfo->SpellFamilyFlags[2] = 0x10; spellInfo->EffectApplyAuraName[1] = SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN; spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Parasitic Shadowfiend Passive ApplySpellFix({ 41013 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_DUMMY; // proc debuff, and summon infinite fiends }); ApplySpellFix({ 27892, // To Anchor 1 27928, // To Anchor 1 27935, // To Anchor 1 27915, // Anchor to Skulls 27931, // Anchor to Skulls 27937 // Anchor to Skulls }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 13; }); // Wrath of the Plaguebringer ApplySpellFix({ 29214, 54836 }, [](SpellEntry* spellInfo) { // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target // this is the only known exception, probably just wrong data spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ALLY; spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_SRC_AREA_ALLY; }); // Wind Shear ApplySpellFix({ 57994 }, [](SpellEntry* spellInfo) { // improper data for EFFECT_1 in 3.3.5 DBC, but is correct in 4.x spellInfo->Effect[EFFECT_1] = SPELL_EFFECT_MODIFY_THREAT_PERCENT; spellInfo->EffectBasePoints[EFFECT_1] = -6; // -5% }); // Improved Devouring Plague ApplySpellFix({ 63675 }, [](SpellEntry* spellInfo) { spellInfo->EffectBonusMultiplier[0] = 0; spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; }); ApplySpellFix({ 8145, // Tremor Totem (instant pulse) 6474 // Earthbind Totem (instant pulse) }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY; }); // Marked for Death ApplySpellFix({ 53241, 53243, 53244, 53245, 53246 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[0] = flag96(423937, 276955137, 2049); }); ApplySpellFix({ 70728, // Exploit Weakness 70840 // Devious Minds }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_PET; }); // Culling The Herd ApplySpellFix({ 70893 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_MASTER; }); // Sigil of the Frozen Conscience ApplySpellFix({ 54800 }, [](SpellEntry* spellInfo) { // change class mask to custom extended flags of Icy Touch // this is done because another spell also uses the same SpellFamilyFlags as Icy Touch // SpellFamilyFlags[0] & 0x00000040 in SPELLFAMILY_DEATHKNIGHT is currently unused (3.3.5a) // this needs research on modifier applying rules, does not seem to be in Attributes fields spellInfo->EffectSpellClassMask[0] = flag96(0x00000040, 0x00000000, 0x00000000); }); // Idol of the Flourishing Life ApplySpellFix({ 64949 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[EFFECT_0] = flag96(0x00000000, 0x02000000, 0x00000000); spellInfo->EffectApplyAuraName[EFFECT_0] = SPELL_AURA_ADD_FLAT_MODIFIER; }); ApplySpellFix({ 34231, // Libram of the Lightbringer 60792, // Libram of Tolerance 64956 // Libram of the Resolute }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[EFFECT_0] = flag96(0x80000000, 0x00000000, 0x00000000); spellInfo->EffectApplyAuraName[EFFECT_0] = SPELL_AURA_ADD_FLAT_MODIFIER; }); ApplySpellFix({ 28851, // Libram of Light 28853, // Libram of Divinity 32403 // Blessed Book of Nagrand }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[EFFECT_0] = flag96(0x40000000, 0x00000000, 0x00000000); spellInfo->EffectApplyAuraName[EFFECT_0] = SPELL_AURA_ADD_FLAT_MODIFIER; }); // Ride Carpet ApplySpellFix({ 45602 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[EFFECT_0] = 0; // force seat 0, vehicle doesn't have the required seat flags for "no seat specified (-1)" }); ApplySpellFix({ 64745, // Item - Death Knight T8 Tank 4P Bonus 64936 // Item - Warrior T8 Protection 4P Bonus }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[EFFECT_0] = 100; // 100% chance of procc'ing, not -10% (chance calculated in PrepareTriggersExecutedOnHit) }); // Easter Lay Noblegarden Egg Aura ApplySpellFix({ 61719 }, [](SpellEntry* spellInfo) { // Interrupt flags copied from aura which this aura is linked with spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE; }); // Bleh, need to change FamilyFlags :/ (have the same as original aura - bad!) ApplySpellFix({ 63510 }, [](SpellEntry* spellInfo) { spellInfo->SpellFamilyFlags[0] = 0; spellInfo->SpellFamilyFlags[2] = 0x4000000; }); ApplySpellFix({ 63514 }, [](SpellEntry* spellInfo) { spellInfo->SpellFamilyFlags[0] = 0; spellInfo->SpellFamilyFlags[2] = 0x2000000; }); ApplySpellFix({ 63531 }, [](SpellEntry* spellInfo) { spellInfo->SpellFamilyFlags[0] = 0; spellInfo->SpellFamilyFlags[2] = 0x8000000; }); // And affecting spells ApplySpellFix({ 20138, // Improved Devotion Aura 20139, 20140 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[1][0] = 0; spellInfo->EffectSpellClassMask[1][2] = 0x2000000; }); ApplySpellFix({ 20254, // Improved concentration aura 20255, 20256 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[1][0] = 0; spellInfo->EffectSpellClassMask[1][2] = 0x4000000; spellInfo->EffectSpellClassMask[2][0] = 0; spellInfo->EffectSpellClassMask[2][2] = 0x4000000; }); ApplySpellFix({ 53379, // Swift Retribution 53484, 53648 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[0][0] = 0; spellInfo->EffectSpellClassMask[0][2] = 0x8000000; }); // Sanctified Retribution ApplySpellFix({ 31869 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[0][0] = 0; spellInfo->EffectSpellClassMask[0][2] = 0x8000000; }); // Seal of Light trigger ApplySpellFix({ 20167 }, [](SpellEntry* spellInfo) { spellInfo->spellLevel = 0; spellInfo->baseLevel = 0; spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; }); // Light's Beacon, Beacon of Light ApplySpellFix({ 53651 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Hand of Reckoning ApplySpellFix({ 62124 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx |= SPELL_ATTR1_CANT_BE_REDIRECTED; }); // Redemption ApplySpellFix({ 7328, 10322, 10324, 20772, 20773, 48949, 48950 }, [](SpellEntry* spellInfo) { spellInfo->SpellFamilyName = SPELLFAMILY_PALADIN; }); ApplySpellFix({ 20184, // Judgement of Justice 20185, // Judgement of Light 20186, // Judgement of Wisdom 68055 // Judgements of the Just }, [](SpellEntry* spellInfo) { // hack for seal of light and few spells, judgement consists of few single casts and each of them can proc // some spell, base one has disabled proc flag but those dont have this flag spellInfo->AttributesEx3 |= SPELL_ATTR3_CANT_TRIGGER_PROC; }); // Blessing of sanctuary stats ApplySpellFix({ 67480 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValue[0] = -1; spellInfo->SpellFamilyName = SPELLFAMILY_UNK1; // allows stacking spellInfo->EffectApplyAuraName[1] = SPELL_AURA_DUMMY; // just a marker }); // Seal of Command trigger ApplySpellFix({ 20424 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 &= ~SPELL_ATTR3_CANT_TRIGGER_PROC; }); ApplySpellFix({ 54968, // Glyph of Holy Light, Damage Class should be magic 53652, // Beacon of Light heal, Damage Class should be magic 53654 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; }); // Furious Howl ApplySpellFix({ 64491, 64492, 64493, 64494, 64495 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_MASTER; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_CASTER; spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_MASTER; }); // Call of the Wild ApplySpellFix({ 53434 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_MASTER; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_MASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_CASTER; spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_CASTER; }); // Wild Hunt ApplySpellFix({ 62758, 62762 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[0] = SPELL_AURA_DUMMY; spellInfo->Effect[1] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[1] = SPELL_AURA_DUMMY; }); // Intervene ApplySpellFix({ 3411 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_STOP_ATTACK_TARGET; spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); // Roar of Sacrifice ApplySpellFix({ 53480 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[1] = SPELL_AURA_SPLIT_DAMAGE_PCT; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_TARGET_ALLY; spellInfo->EffectDieSides[1] = 1; spellInfo->EffectBasePoints[1] = 19; spellInfo->EffectMiscValue[1] = 127; // all schools }); // Silencing Shot ApplySpellFix({ 34490, 41084, 42671 }, [](SpellEntry* spellInfo) { spellInfo->speed = 0.0f; }); // Monstrous Bite ApplySpellFix({ 54680, 55495, 55496, 55497, 55498, 55499 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_CASTER; }); // Hunter's Mark ApplySpellFix({ 1130, 14323, 14324, 14325, 53338 }, [](SpellEntry* spellInfo) { spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); // Cobra Strikes ApplySpellFix({ 53257 }, [](SpellEntry* spellInfo) { spellInfo->procCharges = 2; spellInfo->StackAmount = 0; }); // Kill Command ApplySpellFix({ 34027 }, [](SpellEntry* spellInfo) { spellInfo->procCharges = 0; }); // Kindred Spirits, damage aura ApplySpellFix({ 57458 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx4 |= SPELL_ATTR4_UNK21; }); // Chimera Shot - Serpent trigger ApplySpellFix({ 53353 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; }); // Entrapment trigger ApplySpellFix({ 19185, 64803, 64804 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_DEST_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[EFFECT_0] = TARGET_UNIT_DEST_AREA_ENEMY; spellInfo->AttributesEx5 |= SPELL_ATTR5_SKIP_CHECKCAST_LOS_CHECK; }); // Improved Stings (Rank 2) ApplySpellFix({ 19465 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_2] = TARGET_UNIT_CASTER; }); // Heart of the Phoenix (triggered) ApplySpellFix({ 54114 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx &= ~SPELL_ATTR1_DISMISS_PET; spellInfo->RecoveryTime = 8 * 60 * IN_MILLISECONDS; // prev 600000 }); // Master of Subtlety ApplySpellFix({ 31221, 31222, 31223 }, [](SpellEntry* spellInfo) { spellInfo->SpellFamilyName = SPELLFAMILY_ROGUE; }); ApplySpellFix({ 31666, // Master of Subtlety triggers 58428 // Overkill }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_SCRIPT_EFFECT; }); // Honor Among Thieves ApplySpellFix({ 51698, 51700, 51701 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[0] = 51699; }); ApplySpellFix({ 5171, // Slice and Dice 6774, // Slice and Dice 1725 // Distract }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); // Envenom ApplySpellFix({ 32645, 32684, 57992, 57993 }, [](SpellEntry* spellInfo) { spellInfo->Dispel = DISPEL_NONE; }); ////////////////////////////////////////// ////////// ULDUAR ////////////////////////////////////////// ApplySpellFix({ 64014, 64032, 64028, 64031, 64030, 64029, 64024, 64025, 65042 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[EFFECT_1] = TARGET_DEST_DB; }); // Killing Spree (teleport) ApplySpellFix({ 57840 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 6; // 100 yards }); // Killing Spree ApplySpellFix({ 51690 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx |= SPELL_ATTR1_NOT_BREAK_STEALTH; }); // Blood Tap visual cd reset ApplySpellFix({ 47804 }, [](SpellEntry* spellInfo) { spellInfo->Effect[2] = 0; spellInfo->Effect[1] = 0; spellInfo->runeCostID = 442; }); // Chains of Ice ApplySpellFix({ 45524 }, [](SpellEntry* spellInfo) { spellInfo->Effect[EFFECT_2] = 0; }); // Impurity ApplySpellFix({ 49220, 49633, 49635, 49636, 49638 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[0] = SPELL_AURA_DUMMY; spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; spellInfo->SpellFamilyName = SPELLFAMILY_DEATHKNIGHT; }); // Deadly Aggression (Deadly Gladiator's Death Knight Relic, item: 42620) ApplySpellFix({ 60549 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; }); // Magic Suppression ApplySpellFix({ 49224, 49610, 49611 }, [](SpellEntry* spellInfo) { spellInfo->procCharges = 0; }); // Wandering Plague ApplySpellFix({ 50526 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); // Dancing Rune Weapon ApplySpellFix({ 49028 }, [](SpellEntry* spellInfo) { spellInfo->Effect[2] = 0; spellInfo->procFlags |= PROC_FLAG_DONE_MELEE_AUTO_ATTACK; }); // Death and Decay ApplySpellFix({ 52212 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE; }); // T9 blood plague crit bonus ApplySpellFix({ 67118 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; }); // Pestilence ApplySpellFix({ 50842 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[2] = TARGET_DEST_TARGET_ENEMY; }); // Horn of Winter, stacking issues ApplySpellFix({ 57330, 57623 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[1] = 0; }); // Scourge Strike trigger ApplySpellFix({ 70890 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_CANT_TRIGGER_PROC; }); // Blood-caked Blade - Blood-caked Strike trigger ApplySpellFix({ 50463 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_CANT_TRIGGER_PROC; }); // Blood Gorged ApplySpellFix({ 61274, 61275, 61276, 61277,61278 }, [](SpellEntry* spellInfo) { // ARP affect Death Strike and Rune Strike spellInfo->EffectSpellClassMask[EFFECT_0] = flag96(0x1400011, 0x20000000, 0x0); }); // Death Grip ApplySpellFix({ 49576, 49560 }, [](SpellEntry* spellInfo) { // remove main grip mechanic, leave only effect one // should fix taunt on bosses and not break the pull protection at the same time (no aura provides immunity to grip mechanic) spellInfo->Mechanic = 0; }); // Death Grip Jump Dest ApplySpellFix({ 57604 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Death Pact ApplySpellFix({ 48743 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx &= ~SPELL_ATTR1_CANT_TARGET_SELF; }); // Raise Ally (trigger) ApplySpellFix({ 46619 }, [](SpellEntry* spellInfo) { spellInfo->Attributes &= ~SPELL_ATTR0_CANT_CANCEL; }); // Frost Strike ApplySpellFix({ 49143, 51416, 51417, 51418, 51419, 55268 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_BLOCKABLE_SPELL; }); // Death Knight T10 Tank 2p Bonus ApplySpellFix({ 70650 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_ADD_PCT_MODIFIER; }); ApplySpellFix({ 45297, 45284 }, [](SpellEntry* spellInfo) { spellInfo->CategoryRecoveryTime = 0; spellInfo->RecoveryTime = 0; spellInfo->AttributesEx6 |= SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS; }); // Improved Earth Shield ApplySpellFix({ 51560, 51561 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValue[1] = SPELLMOD_DAMAGE; }); // Tidal Force ApplySpellFix({ 55166, 55198 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 18; spellInfo->procCharges = 0; }); // Healing Stream Totem ApplySpellFix({ 52042 }, [](SpellEntry* spellInfo) { spellInfo->spellLevel = 0; spellInfo->baseLevel = 0; spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; }); // Earth Shield ApplySpellFix({ 379 }, [](SpellEntry* spellInfo) { spellInfo->spellLevel = 0; spellInfo->baseLevel = 0; spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; }); // Stormstrike ApplySpellFix({ 17364 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Strength of Earth totem effect ApplySpellFix({ 8076, 8162, 8163, 10441, 25362, 25527, 57621, 58646 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[1] = spellInfo->EffectRadiusIndex[0]; spellInfo->EffectRadiusIndex[2] = spellInfo->EffectRadiusIndex[0]; }); // Flametongue Totem effect ApplySpellFix({ 52109, 52110, 52111, 52112, 52113, 58651, 58654, 58655 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[2] = spellInfo->EffectImplicitTargetB[1] = spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->EffectImplicitTargetA[2] = spellInfo->EffectImplicitTargetA[1] = spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; }); // Sentry Totem ApplySpellFix({ 6495 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 0; }); // Bind Sight (PT) ApplySpellFix({ 6277 }, [](SpellEntry* spellInfo) { // because it is passive, needs this to be properly removed at death in RemoveAllAurasOnDeath() spellInfo->AttributesEx &= ~SPELL_ATTR1_CHANNELED_1; spellInfo->Attributes |= SPELL_ATTR0_PASSIVE; spellInfo->AttributesEx7 |= SPELL_ATTR7_REACTIVATE_AT_RESURRECT; }); // Ancestral Awakening Heal ApplySpellFix({ 52752 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; }); // Heroism ApplySpellFix({ 32182 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 57723; // Exhaustion spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Bloodlust ApplySpellFix({ 2825 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 57724; // Sated spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Improved Succubus ApplySpellFix({ 18754, 18755, 18756 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; }); // Unstable Affliction ApplySpellFix({ 31117 }, [](SpellEntry* spellInfo) { spellInfo->PreventionType = SPELL_PREVENTION_TYPE_NONE; }); // Shadowflame - trigger ApplySpellFix({ 47960, // r1 61291 // r2 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx |= SPELL_ATTR1_CANT_BE_REDIRECTED; }); // Curse of Doom ApplySpellFix({ 18662 }, [](SpellEntry* spellInfo) { // summoned doomguard duration fix spellInfo->DurationIndex = 6; }); // Glyph of Voidwalker ApplySpellFix({ 56247 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[EFFECT_0] = SPELL_AURA_ADD_FLAT_MODIFIER; spellInfo->EffectMiscValue[EFFECT_0] = SPELLMOD_EFFECT1; spellInfo->EffectSpellClassMask[EFFECT_0] = flag96(0x8000000, 0, 0); }); // Everlasting Affliction ApplySpellFix({ 47201, 47202, 47203, 47204, 47205 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[1][0] |= 2; // add corruption to affected spells }); // Death's Embrace ApplySpellFix({ 47198, 47199, 47200 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[1][0] |= 0x4000; // include Drain Soul }); // Improved Demonic Tactics ApplySpellFix({ 54347, 54348, 54349 }, [](SpellEntry* spellInfo) { spellInfo->Effect[EFFECT_1] = spellInfo->Effect[EFFECT_0]; spellInfo->EffectApplyAuraName[EFFECT_1] = spellInfo->EffectApplyAuraName[EFFECT_0]; spellInfo->EffectImplicitTargetA[EFFECT_1] = spellInfo->EffectImplicitTargetA[EFFECT_0]; spellInfo->EffectMiscValue[EFFECT_0] = SPELLMOD_EFFECT1; spellInfo->EffectMiscValue[EFFECT_1] = SPELLMOD_EFFECT2; }); // Rain of Fire (Doomguard) ApplySpellFix({ 42227 }, [](SpellEntry* spellInfo) { spellInfo->speed = 0.0f; }); // Ritual Enslavement ApplySpellFix({ 22987 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[EFFECT_0] = SPELL_AURA_MOD_CHARM; }); // Combustion, make this passive ApplySpellFix({ 11129 }, [](SpellEntry* spellInfo) { spellInfo->Dispel = DISPEL_NONE; }); // Magic Absorption ApplySpellFix({ 29441, 29444 }, [](SpellEntry* spellInfo) { spellInfo->spellLevel = 0; }); // Living Bomb ApplySpellFix({ 44461, 55361, 55362 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; spellInfo->AttributesEx4 |= SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS; }); // Evocation ApplySpellFix({ 12051 }, [](SpellEntry* spellInfo) { spellInfo->InterruptFlags |= SPELL_INTERRUPT_FLAG_INTERRUPT; }); // MI Fireblast, WE Frostbolt, MI Frostbolt ApplySpellFix({ 59637, 31707, 72898 }, [](SpellEntry* spellInfo) { spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; }); // Blazing Speed ApplySpellFix({ 31641, 31642 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[0] = 31643; }); // Summon Water Elemental (permanent) ApplySpellFix({ 70908 }, [](SpellEntry* spellInfo) { // treat it as pet spellInfo->Effect[0] = SPELL_EFFECT_SUMMON_PET; }); // // Burnout, trigger ApplySpellFix({ 44450 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_POWER_BURN; }); // Mirror Image - Summon Spells ApplySpellFix({ 58831, 58833, 58834, 65047 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_DEST_CASTER; spellInfo->EffectRadiusIndex[EFFECT_0] = 0; }); // Initialize Images (Mirror Image) ApplySpellFix({ 58836 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_1] = TARGET_UNIT_CASTER; }); // Arcane Blast, can't be dispelled ApplySpellFix({ 36032 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY; }); // Chilled (frost armor, ice armor proc) ApplySpellFix({ 6136, 7321 }, [](SpellEntry* spellInfo) { spellInfo->PreventionType = SPELL_PREVENTION_TYPE_NONE; }); // Mirror Image Frostbolt ApplySpellFix({ 59638 }, [](SpellEntry* spellInfo) { spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; spellInfo->SpellFamilyName = SPELLFAMILY_MAGE; spellInfo->SpellFamilyFlags = flag96(0x20, 0x0, 0x0); }); // Fingers of Frost ApplySpellFix({ 44544 }, [](SpellEntry* spellInfo) { spellInfo->Dispel = DISPEL_NONE; spellInfo->AttributesEx4 |= SPELL_ATTR4_NOT_STEALABLE; spellInfo->EffectSpellClassMask[0] = flag96(685904631, 1151040, 32); }); // Fingers of Frost visual buff ApplySpellFix({ 74396 }, [](SpellEntry* spellInfo) { spellInfo->procCharges = 2; spellInfo->StackAmount = 0; }); // Glyph of blocking ApplySpellFix({ 58375 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[0] = 58374; }); // Sweeping Strikes stance change ApplySpellFix({ 12328 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_NOT_SHAPESHIFT; }); // Damage Shield ApplySpellFix({ 59653 }, [](SpellEntry* spellInfo) { spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; spellInfo->spellLevel = 0; }); ApplySpellFix({ 20230, // Retaliation 871, // Shield Wall 1719 // Recklessness }, [](SpellEntry* spellInfo) { // Strange shared cooldown spellInfo->AttributesEx6 |= SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS; }); // Vigilance ApplySpellFix({ 50720 }, [](SpellEntry* spellInfo) { // fixes bug with empowered renew, single target aura spellInfo->SpellFamilyName = SPELLFAMILY_WARRIOR; }); // Sunder Armor ApplySpellFix({ 58567 }, [](SpellEntry* spellInfo) { // trigger, remove spellfamilyflags because of glyph of sunder armor spellInfo->SpellFamilyFlags = flag96(0x0, 0x0, 0x0); }); // Sunder Armor - Old Ranks ApplySpellFix({ 7405, 8380, 11596, 11597, 25225, 47467 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[EFFECT_0] = 11971; spellInfo->Effect[EFFECT_0] = SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE; }); // Improved Spell Reflection ApplySpellFix({ 59725 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_UNIT_CASTER_AREA_PARTY; }); // Shadow Weaving ApplySpellFix({ 15257, 15331, 15332 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PROC_TRIGGER_SPELL; }); // Hymn of Hope ApplySpellFix({ 64904 }, [](SpellEntry* spellInfo) { // rewrite part of aura system or swap effects... spellInfo->EffectApplyAuraName[1] = SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT; spellInfo->Effect[2] = spellInfo->Effect[0]; spellInfo->Effect[0] = 0; spellInfo->EffectDieSides[2] = spellInfo->EffectDieSides[0]; spellInfo->EffectImplicitTargetA[2] = spellInfo->EffectImplicitTargetB[0]; spellInfo->EffectRadiusIndex[2] = spellInfo->EffectRadiusIndex[0]; spellInfo->EffectBasePoints[2] = spellInfo->EffectBasePoints[0]; }); // Divine Hymn ApplySpellFix({ 64844 }, [](SpellEntry* spellInfo) { spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; spellInfo->spellLevel = 0; }); ApplySpellFix({ 14898, // Spiritual Healing affects prayer of mending 15349, 15354, 15355, 15356, 47562, // Divine Providence affects prayer of mending 47564, 47565, 47566, 47567, 47586, // Twin Disciplines affects prayer of mending 47587, 47588, 52802, 52803 }, [](SpellEntry* spellInfo) { spellInfo->EffectSpellClassMask[0][1] |= 0x20; // prayer of mending }); // Power Infusion ApplySpellFix({ 10060 }, [](SpellEntry* spellInfo) { // hack to fix stacking with arcane power spellInfo->Effect[EFFECT_2] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[EFFECT_2] = SPELL_AURA_ADD_PCT_MODIFIER; spellInfo->EffectImplicitTargetA[EFFECT_2] = TARGET_UNIT_TARGET_ALLY; }); // Lifebloom final bloom ApplySpellFix({ 33778 }, [](SpellEntry* spellInfo) { spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; spellInfo->spellLevel = 0; spellInfo->SpellFamilyFlags = flag96(0, 0x10, 0); }); // Clearcasting ApplySpellFix({ 16870 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 31; // 8 secs }); // Owlkin Frenzy ApplySpellFix({ 48391 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_NOT_SHAPESHIFT; }); // Item T10 Restoration 4P Bonus ApplySpellFix({ 70691 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; }); ApplySpellFix({ 770, // Faerie Fire 16857 // Faerie Fire (Feral) }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx &= ~SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE; }); // Feral Charge - Cat ApplySpellFix({ 49376, 61138, 61132, 50259 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); // Glyph of Barkskin ApplySpellFix({ 63058 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[EFFECT_0] = SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE; }); // Resurrection Sickness ApplySpellFix({ 15007 }, [](SpellEntry* spellInfo) { spellInfo->SpellFamilyName = SPELLFAMILY_GENERIC; }); // Luck of the Draw ApplySpellFix({ 72221 }, [](SpellEntry* spellInfo) { spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; }); // Bind ApplySpellFix({ 3286 }, [](SpellEntry* spellInfo) { spellInfo->Targets = 0; // neutral innkeepers not friendly? spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_TARGET_ANY; }); // Playback Speech ApplySpellFix({ 74209 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 1; }); ApplySpellFix({ 2641, // Dismiss Pet 23356 // Taming Lesson }, [](SpellEntry* spellInfo) { // remove creaturetargettype spellInfo->TargetCreatureType = 0; }); // Aspect of the Viper ApplySpellFix({ 34074 }, [](SpellEntry* spellInfo) { spellInfo->Effect[2] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectImplicitTargetA[2] = 1; spellInfo->EffectApplyAuraName[2] = SPELL_AURA_DUMMY; }); // Strength of Wrynn ApplySpellFix({ 60509 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[2] = 1500; spellInfo->EffectBasePoints[1] = 150; spellInfo->EffectApplyAuraName[1] = SPELL_AURA_PERIODIC_HEAL; }); // Winterfin First Responder ApplySpellFix({ 48739 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 1; spellInfo->EffectRealPointsPerLevel[0] = 0; spellInfo->EffectDieSides[0] = 0; spellInfo->EffectDamageMultiplier[0] = 0; spellInfo->EffectBonusMultiplier[0] = 0; }); // Army of the Dead (trigger npc aura) ApplySpellFix({ 49099 }, [](SpellEntry* spellInfo) { spellInfo->EffectAmplitude[0] = 15000; }); // Isle of Conquest ApplySpellFix({ 66551 }, [](SpellEntry* spellInfo) { // Teleport in, missing range spellInfo->rangeIndex = 13; // 50000yd }); // A'dal's Song of Battle ApplySpellFix({ 39953 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetA[EFFECT_1] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetA[EFFECT_2] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[EFFECT_0] = TARGET_UNIT_SRC_AREA_ALLY; spellInfo->EffectImplicitTargetB[EFFECT_1] = TARGET_UNIT_SRC_AREA_ALLY; spellInfo->EffectImplicitTargetB[EFFECT_2] = TARGET_UNIT_SRC_AREA_ALLY; spellInfo->DurationIndex = 367; // 2 Hours }); ApplySpellFix({ 57607, // WintergraspCatapult - Spell Plague Barrel - EffectRadiusIndex 57619, // WintergraspDemolisher - Spell Hourl Boulder - EffectRadiusIndex 57610 // Cannon (Siege Turret) }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_25_YARDS; // SPELL_EFFECT_WMO_DAMAGE }); // WintergraspCannon - Spell Fire Cannon - EffectRadiusIndex ApplySpellFix({ 51422 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_10_YARDS; // SPELL_EFFECT_SCHOOL_DAMAGE }); // WintergraspDemolisher - Spell Ram - EffectRadiusIndex ApplySpellFix({ 54107 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_3_YARDS; // SPELL_EFFECT_KNOCK_BACK spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_3_YARDS; // SPELL_EFFECT_SCHOOL_DAMAGE spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_3_YARDS; // SPELL_EFFECT_WEAPON_DAMAGE }); // WintergraspSiegeEngine - Spell Ram - EffectRadiusIndex ApplySpellFix({ 51678 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_10_YARDS; // SPELL_EFFECT_KNOCK_BACK spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_10_YARDS; // SPELL_EFFECT_SCHOOL_DAMAGE spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_20_YARDS; // SPELL_EFFECT_WEAPON_DAMAGE }); // WintergraspCatapult - Spell Plague Barrell - Range ApplySpellFix({ 57606 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 164; // "Catapult Range" }); // Boulder (Demolisher) ApplySpellFix({ 50999 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = 13; // 10yd }); // Flame Breath (Catapult) ApplySpellFix({ 50990 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = 19; // 18yd }); // Jormungar Bite ApplySpellFix({ 56103 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_UNIT_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[EFFECT_0] = 0; }); // Throw Proximity Bomb ApplySpellFix({ 34095 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_DEST_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[EFFECT_0] = 0; }); ApplySpellFix({ 53348, // DEATH KNIGHT SCARLET FIRE ARROW 53117 // BALISTA }, [](SpellEntry* spellInfo) { spellInfo->RecoveryTime = 5000; spellInfo->CategoryRecoveryTime = 5000; }); // Teleport To Molten Core ApplySpellFix({ 25139 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_DEATH_PERSISTENT; }); // Landen Stilwell Transform ApplySpellFix({ 31310 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_PASSIVE; }); // Shadowstalker Stealth ApplySpellFix({ 5916 }, [](SpellEntry* spellInfo) { spellInfo->EffectRealPointsPerLevel[EFFECT_0] = 5.0f; }); // Sneak ApplySpellFix({ 22766 }, [](SpellEntry* spellInfo) { spellInfo->EffectRealPointsPerLevel[EFFECT_0] = 5.0f; }); // Murmur's Touch ApplySpellFix({ 38794, 33711 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; spellInfo->EffectTriggerSpell[0] = 33760; }); // Negaton Field ApplySpellFix({ 36729, // Normal 38834 // Heroic }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Curse of the Doomsayer NORMAL ApplySpellFix({ 36173 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[0] = 36174; // Currently triggers heroic version... }); // Crystal Channel ApplySpellFix({ 34156 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 35; // 35yd; spellInfo->ChannelInterruptFlags |= AURA_INTERRUPT_FLAG_MOVE; }); // Debris ApplySpellFix({ 36449 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1; }); // Soul Channel ApplySpellFix({ 30531 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Debris Visual ApplySpellFix({ 30632 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[0] = TARGET_DEST_DYNOBJ_ALLY; }); // Activate Sunblade Protecto ApplySpellFix({ 46475, 46476 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 14; // 60yd }); // Break Ice ApplySpellFix({ 46638 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 &= ~SPELL_ATTR3_ONLY_TARGET_PLAYERS; // Obvious fail, it targets gameobject... }); // Sinister Reflection Clone ApplySpellFix({ 45785 }, [](SpellEntry* spellInfo) { spellInfo->speed = 0.0f; }); // Armageddon ApplySpellFix({ 45909 }, [](SpellEntry* spellInfo) { spellInfo->speed = 8.0f; }); // Spell Absorption ApplySpellFix({ 41034 }, [](SpellEntry* spellInfo) { spellInfo->Effect[EFFECT_2] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[EFFECT_2] = SPELL_AURA_SCHOOL_ABSORB; spellInfo->EffectImplicitTargetA[EFFECT_2] = TARGET_UNIT_CASTER; spellInfo->EffectMiscValue[EFFECT_2] = SPELL_SCHOOL_MASK_MAGIC; }); // Shared Bonds ApplySpellFix({ 41363 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx &= ~SPELL_ATTR1_CHANNELED_1; }); ApplySpellFix({ 41485, // Deadly Poison 41487 // Envenom }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE; }); // Parasitic Shadowfiend ApplySpellFix({ 41914 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1; spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Teleport Maiev ApplySpellFix({ 41221 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 13; // 0-50000yd }); // Watery Grave Explosion ApplySpellFix({ 37852 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx5 |= SPELL_ATTR5_USABLE_WHILE_STUNNED; }); // Amplify Damage ApplySpellFix({ 39095 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; }); // Energy Feedback ApplySpellFix({ 44335 }, [](SpellEntry* spellInfo) { spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; }); ApplySpellFix({ 31984, // Finger of Death 35354 // Hand of Death }, [](SpellEntry* spellInfo) { // Spell doesn't need to ignore invulnerabilities spellInfo->Attributes = SPELL_ATTR0_ABILITY; }); // Finger of Death ApplySpellFix({ 32111 }, [](SpellEntry* spellInfo) { spellInfo->CastingTimeIndex = 0; // We only need the animation, no damage }); // Flame Breath, catapult spell ApplySpellFix({ 50989 }, [](SpellEntry* spellInfo) { spellInfo->Attributes &= ~SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION; }); // Koralon, Flaming Cinder ApplySpellFix({ 66690 }, [](SpellEntry* spellInfo) { // missing radius index spellInfo->EffectRadiusIndex[0] = 12; //100yd spellInfo->MaxAffectedTargets = 1; }); // Acid Volley ApplySpellFix({ 54714, 29325 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; }); // Summon Plagued Warrior ApplySpellFix({ 29237 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_DUMMY; spellInfo->Effect[1] = spellInfo->Effect[2] = 0; }); // Icebolt ApplySpellFix({ 28526 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; }); // Infected Wound ApplySpellFix({ 29306 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Hopeless ApplySpellFix({ 29125 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENTRY; }); // Jagged Knife ApplySpellFix({ 55550 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_REQ_AMMO; }); // Moorabi - Transformation ApplySpellFix({ 55098 }, [](SpellEntry* spellInfo) { spellInfo->InterruptFlags |= SPELL_INTERRUPT_FLAG_INTERRUPT; }); ApplySpellFix({ 55521, // Poisoned Spear (Normal) 58967, // Poisoned Spear (Heroic) 55348, // Throw (Normal) 58966 // Throw (Heroic) }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_REQ_AMMO; }); // Charged Chaotic rift aura, trigger ApplySpellFix({ 47737 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 37; // 50yd }); // Vanish ApplySpellFix({ 55964 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); // Trollgore - Summon Drakkari Invader ApplySpellFix({ 49456, 49457, 49458 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB; }); ApplySpellFix({ 48278, // Paralyse 47669 // Awaken subboss }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[0] = 0; }); // Flame Breath ApplySpellFix({ 47592 }, [](SpellEntry* spellInfo) { spellInfo->EffectAmplitude[0] = 200; }); // Skarvald, Charge ApplySpellFix({ 43651 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 13; // 0-50000yd }); // Ingvar the Plunderer, Woe Strike ApplySpellFix({ 42730 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[1] = 42739; }); ApplySpellFix({ 59735 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[1] = 59736; }); // Ingvar the Plunderer, Ingvar transform ApplySpellFix({ 42796 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_DEATH_PERSISTENT; }); ApplySpellFix({ 42772, // Hurl Dagger (Normal) 59685 // Hurl Dagger (Heroic) }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_REQ_AMMO; }); // Control Crystal Activation ApplySpellFix({ 57804 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = 1; spellInfo->EffectImplicitTargetB[0] = 0; }); // Destroy Door Seal ApplySpellFix({ 58040 }, [](SpellEntry* spellInfo) { spellInfo->ChannelInterruptFlags &= ~(AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE); }); // Ichoron, Water Blast ApplySpellFix({ 54237, 59520 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); // Krik'thir - Mind Flay ApplySpellFix({ 52586, 59367 }, [](SpellEntry* spellInfo) { spellInfo->ChannelInterruptFlags |= AURA_INTERRUPT_FLAG_MOVE; }); // Glare of the Tribunal ApplySpellFix({ 50988, 59870 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[0] = 0; }); // Static Charge ApplySpellFix({ 50835, 59847 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ALLY; }); // Lava Strike damage ApplySpellFix({ 57697 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Lava Strike trigger ApplySpellFix({ 57578 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; }); // Gift of Twilight Shadow/Fire ApplySpellFix({ 57835, 58766 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx &= ~SPELL_ATTR1_CHANNELED_1; }); // Pyrobuffet ApplySpellFix({ 57557 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 56911; }); // Arcane Barrage ApplySpellFix({ 56397 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[1] = 0; spellInfo->EffectImplicitTargetA[2] = TARGET_UNIT_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[2] = 0; }); ApplySpellFix({ 55849, // Power Spark (ground +50% dmg aura) 56438, // Arcane Overload (-50% dmg taken) - this is to prevent apply -> unapply -> apply ... dunno whether it's correct }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Vortex (Control Vehicle) ApplySpellFix({ 56263 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); // Haste (Nexus Lord, increase run speed of the disk) ApplySpellFix({ 57060 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[2] = TARGET_UNIT_VEHICLE; }); // Arcane Overload ApplySpellFix({ 56430 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_TRIGGER_MISSILE; spellInfo->EffectTriggerSpell[0] = 56429; }); // Summon Arcane Bomb ApplySpellFix({ 56429 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->EffectImplicitTargetA[1] = 0; spellInfo->EffectImplicitTargetB[1] = 0; spellInfo->EffectImplicitTargetA[2] = 0; spellInfo->EffectImplicitTargetB[2] = 0; }); // Destroy Platform Event ApplySpellFix({ 59099 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[1] = 22; spellInfo->EffectImplicitTargetB[1] = 15; spellInfo->EffectImplicitTargetA[2] = 22; spellInfo->EffectImplicitTargetB[2] = 15; }); // Surge of Power (Phase 3) ApplySpellFix({ 57407, // N }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; spellInfo->InterruptFlags = 0; spellInfo->EffectRadiusIndex[0] = 28; spellInfo->AttributesEx4 |= SPELL_ATTR4_CAN_CAST_WHILE_CASTING; spellInfo->EffectImplicitTargetA[0] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENEMY; spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Surge of Power (Phase 3) ApplySpellFix({ 60936 // H }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 3; spellInfo->InterruptFlags = 0; spellInfo->EffectRadiusIndex[0] = 28; spellInfo->AttributesEx4 |= SPELL_ATTR4_CAN_CAST_WHILE_CASTING; spellInfo->EffectImplicitTargetA[0] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENEMY; spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Wyrmrest Drake - Life Burst ApplySpellFix({ 57143 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; spellInfo->EffectImplicitTargetA[0] = 0; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->EffectImplicitTargetA[1] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_SRC_AREA_ALLY; spellInfo->EffectPointsPerComboPoint[1] = 2500; spellInfo->EffectBasePoints[1] = 2499; spellInfo->rangeIndex = 1; spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); //Alexstrasza - Gift ApplySpellFix({ 61028 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Vortex (freeze anim) ApplySpellFix({ 55883 }, [](SpellEntry* spellInfo) { spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; }); // Hurl Pyrite ApplySpellFix({ 62490 }, [](SpellEntry* spellInfo) { spellInfo->Effect[EFFECT_1] = 0; }); // Ulduar, Mimiron, Magnetic Core (summon) ApplySpellFix({ 64444 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_CASTER; }); // Ulduar, Mimiron, bomb bot explosion ApplySpellFix({ 63801 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValue[1] = 17286; }); // Ulduar, Mimiron, Summon Flames Initial ApplySpellFix({ 64563 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; spellInfo->EffectImplicitTargetB[0] = 0; }); // Ulduar, Mimiron, Flames (damage) ApplySpellFix({ 64566 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; spellInfo->AttributesEx4 &= ~SPELL_ATTR4_IGNORE_RESISTANCES; }); // Ulduar, Hodir, Starlight ApplySpellFix({ 62807 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 16; // 1yd }); // Ulduar, General Vezax, Mark of the Faceless ApplySpellFix({ 63278 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; }); // Boom (XT-002) ApplySpellFix({ 62834 }, [](SpellEntry* spellInfo) { spellInfo->Effect[EFFECT_1] = 0; }); // Supercharge ApplySpellFix({ 61920 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Lightning Whirl ApplySpellFix({ 61916 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 3; }); ApplySpellFix({ 63482 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 8; }); // Stone Grip, remove absorb aura ApplySpellFix({ 62056, 63985 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; }); // Sentinel Blast ApplySpellFix({ 64389, 64678 }, [](SpellEntry* spellInfo) { spellInfo->Dispel = DISPEL_MAGIC; }); // Potent Pheromones ApplySpellFix({ 62619 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; }); // Healthy spore summon periodic ApplySpellFix({ 62566 }, [](SpellEntry* spellInfo) { spellInfo->EffectAmplitude[0] = 2000; spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_TRIGGER_SPELL; }); // Brightleaf Essence trigger ApplySpellFix({ 62968 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; // duplicate }); // Potent Pheromones ApplySpellFix({ 64321 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_ONLY_TARGET_PLAYERS; spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; }); // Lightning Orb Charged ApplySpellFix({ 62186 }, [](SpellEntry* spellInfo) { spellInfo->EffectAmplitude[0] = 5000; // Duration 5 secs, amplitude 8 secs... }); // Lightning Pillar ApplySpellFix({ 62976 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 6; spellInfo->DurationIndex = 28; }); // Sif's Blizzard ApplySpellFix({ 62576, 62602 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 14; // 8yd spellInfo->EffectRadiusIndex[1] = 14; // 8yd }); // Protective Gaze ApplySpellFix({ 64175 }, [](SpellEntry* spellInfo) { spellInfo->RecoveryTime = 25000; }); // Shadow Beacon ApplySpellFix({ 64465 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[0] = 64467; // why do they need two script effects :/ (this one has visual effect) }); // Sanity ApplySpellFix({ 63050 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE; }); // Shadow Nova ApplySpellFix({ 62714, 65209 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); // Cosmic Smash (Algalon the Observer) ApplySpellFix({ 62293 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[0] = TARGET_DEST_CASTER; }); // Cosmic Smash (Algalon the Observer) ApplySpellFix({ 62311, 64596 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; spellInfo->EffectRadiusIndex[0] = 12; // 100yd spellInfo->rangeIndex = 13; // 50000yd }); // Constellation Phase Effect ApplySpellFix({ 65509 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; }); // Black Hole ApplySpellFix({ 62168, 65250, 62169 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1; }); // Ground Slam ApplySpellFix({ 62625 }, [](SpellEntry* spellInfo) { spellInfo->InterruptFlags |= SPELL_INTERRUPT_FLAG_INTERRUPT; }); // Onyxia's Lair, Onyxia, Flame Breath (TriggerSpell = 0 and spamming errors in console) ApplySpellFix({ 18435 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; }); // Onyxia's Lair, Onyxia, Create Onyxia Spawner ApplySpellFix({ 17647 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 37; }); ApplySpellFix({ 17646, // Onyxia's Lair, Onyxia, Summon Onyxia Whelp 68968 // Onyxia's Lair, Onyxia, Summon Lair Guard }, [](SpellEntry* spellInfo) { spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION; spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; spellInfo->rangeIndex = 13; spellInfo->DurationIndex = 5; }); // Onyxia's Lair, Onyxia, Eruption ApplySpellFix({ 17731, 69294 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = SPELL_EFFECT_DUMMY; spellInfo->CastingTimeIndex = 3; spellInfo->EffectRadiusIndex[1] = 19; // 18yd instead of 13yd to make sure all cracks erupt }); // Onyxia's Lair, Onyxia, Breath ApplySpellFix({ 18576, 18578, 18579, 18580, 18581, 18582, 18583, 18609, 18611, 18612, 18613, 18614, 18615, 18616, 18584, 18585, 18586, 18587, 18588, 18589, 18590, 18591, 18592, 18593, 18594, 18595, 18564, 18565, 18566, 18567, 18568, 18569, 18570, 18571, 18572, 18573, 18574, 18575, 18596, 18597, 18598, 18599, 18600, 18601, 18602, 18603, 18604, 18605, 18606, 18607, 18617, 18619, 18620, 18621, 18622, 18623, 18624, 18625, 18626, 18627, 18628, 18618, 18351, 18352, 18353, 18354, 18355, 18356, 18357, 18358, 18359, 18360, 18361, 17086, 17087, 17088, 17089, 17090, 17091, 17092, 17093, 17094, 17095, 17097, 22267, 22268, 21132, 21133, 21135, 21136, 21137, 21138, 21139 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 328; // 250ms spellInfo->EffectImplicitTargetA[1] = 1; if (spellInfo->Effect[1]) { spellInfo->Effect[1] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[1] = SPELL_AURA_PERIODIC_TRIGGER_SPELL; spellInfo->EffectAmplitude[1] = ((spellInfo->CastingTimeIndex == 170) ? 50 : 215); } }); ApplySpellFix({ 48760, // Oculus, Teleport to Coldarra DND 49305 // Oculus, Teleport to Boss 1 DND }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = 25; spellInfo->EffectImplicitTargetB[0] = 17; }); // Oculus, Drake spell Stop Time ApplySpellFix({ 49838 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; spellInfo->excludeTargetAuraSpell = 51162; // exclude planar shift spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_150_YARDS; }); // Oculus, Varos Cloudstrider, Energize Cores ApplySpellFix({ 61407, 62136, 56251, 54069 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CONE_ENTRY; spellInfo->EffectImplicitTargetB[0] = 0; }); // Halls of Lightning, Arc Weld ApplySpellFix({ 59086 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = 1; }); // Halls of Lightning, Arcing Burn ApplySpellFix({ 52671, 59834 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Trial of the Champion, Death's Respite ApplySpellFix({ 68306 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = 25; spellInfo->EffectImplicitTargetA[1] = 25; }); // Trial of the Champion, Eadric Achievement (The Faceroller) ApplySpellFix({ 68197 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ALLY; spellInfo->Attributes |= SPELL_ATTR0_CASTABLE_WHILE_DEAD; }); // Trial of the Champion, Earth Shield ApplySpellFix({ 67530 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PROC_TRIGGER_SPELL; // will trigger 67537 }); // Trial of the Champion, Hammer of the Righteous ApplySpellFix({ 66867 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_DUMMY; }); // Trial of the Champion, Summon Risen Jaeren/Arelas ApplySpellFix({ 67705, 67715 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_DEAD; }); // Trial of the Champion, Ghoul Explode ApplySpellFix({ 67751 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENTRY; spellInfo->EffectRadiusIndex[0] = 12; spellInfo->EffectImplicitTargetA[1] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_SRC_AREA_ENTRY; spellInfo->EffectRadiusIndex[1] = 12; spellInfo->EffectImplicitTargetA[2] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[2] = TARGET_UNIT_SRC_AREA_ENTRY; spellInfo->EffectRadiusIndex[2] = 12; }); // Trial of the Champion, Desecration ApplySpellFix({ 67778, 67877 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[0] = 68766; }); // Trial of the Crusader, Jaraxxus Intro spell ApplySpellFix({ 67888 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_STOP_ATTACK_TARGET; spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT; spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); // Trial of the Crusader, Lich King Intro spell ApplySpellFix({ 68193 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENEMY; }); // Trial of the Crusader, Gormok, player vehicle spell, CUSTOM! (default jump to hand, not used) ApplySpellFix({ 66342 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[0] = SPELL_AURA_SET_VEHICLE_ID; spellInfo->EffectMiscValue[0] = 496; spellInfo->DurationIndex = 21; spellInfo->rangeIndex = 13; spellInfo->EffectImplicitTargetA[0] = 25; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_CHANGE_MAP; }); // Trial of the Crusader, Gormok, Fire Bomb ApplySpellFix({ 66313 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[0] = TARGET_DEST_TARGET_ANY; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[1] = TARGET_DEST_TARGET_ANY; spellInfo->Effect[1] = 0; }); ApplySpellFix({ 66317 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_STOP_ATTACK_TARGET; spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT; spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); ApplySpellFix({ 66318 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->speed = 14.0f; spellInfo->Attributes |= SPELL_ATTR0_STOP_ATTACK_TARGET; spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT; spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); ApplySpellFix({ 66320, 67472, 67473, 67475 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 7; spellInfo->EffectRadiusIndex[1] = 7; }); // Trial of the Crusader, Acidmaw & Dreadscale, Emerge ApplySpellFix({ 66947 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx5 |= SPELL_ATTR5_USABLE_WHILE_STUNNED; }); // Trial of the Crusader, Jaraxxus, Curse of the Nether ApplySpellFix({ 66211 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 66209; // exclude Touch of Jaraxxus }); // Trial of the Crusader, Jaraxxus, Summon Volcano ApplySpellFix({ 66258, 67901 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 85; // summon for 18 seconds, 15 not enough }); // Trial of the Crusader, Jaraxxus, Spinning Pain Spike ApplySpellFix({ 66281 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 26; }); ApplySpellFix({ 66287 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[1] = SPELL_AURA_MOD_TAUNT; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_NEARBY_ENTRY; spellInfo->Effect[2] = SPELL_EFFECT_APPLY_AURA; spellInfo->EffectApplyAuraName[2] = SPELL_AURA_MOD_STUN; spellInfo->EffectImplicitTargetA[2] = TARGET_UNIT_CASTER; spellInfo->DurationIndex = 35; // 4 secs }); // Trial of the Crusader, Jaraxxus, Fel Fireball ApplySpellFix({ 66532, 66963, 66964, 66965 }, [](SpellEntry* spellInfo) { spellInfo->InterruptFlags |= SPELL_INTERRUPT_FLAG_INTERRUPT; }); // tempfix, make Nether Power not stealable ApplySpellFix({ 66228, 67106, 67107, 67108 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx4 |= SPELL_ATTR4_NOT_STEALABLE; }); // Trial of the Crusader, Faction Champions, Druid - Tranquality ApplySpellFix({ 66086, 67974, 67975, 67976 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AREA_AURA_FRIEND; }); // Trial of the Crusader, Faction Champions, Shaman - Earth Shield ApplySpellFix({ 66063 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PROC_TRIGGER_SPELL; spellInfo->EffectTriggerSpell[0] = 66064; }); // Trial of the Crusader, Faction Champions, Priest - Mana Burn ApplySpellFix({ 66100 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 5; spellInfo->EffectDieSides[0] = 0; }); ApplySpellFix({ 68026 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 8; spellInfo->EffectDieSides[0] = 0; }); ApplySpellFix({ 68027 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 6; spellInfo->EffectDieSides[0] = 0; }); ApplySpellFix({ 68028 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 10; spellInfo->EffectDieSides[0] = 0; }); // Trial of the Crusader, Twin Valkyr, Touch of Light/Darkness, Light/Dark Surge ApplySpellFix({ 65950 // light 0 }, [](SpellEntry* spellInfo) { //spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; spellInfo->EffectImplicitTargetA[0] = 6; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); ApplySpellFix({ 65767 // light surge 0 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 65686; }); ApplySpellFix({ 67296 // light 1 }, [](SpellEntry* spellInfo) { //spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; spellInfo->EffectImplicitTargetA[0] = 6; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); ApplySpellFix({ 67274 // light surge 1 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 67222; }); ApplySpellFix({ 67297 // light 2 }, [](SpellEntry* spellInfo) { //spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; spellInfo->EffectImplicitTargetA[0] = 6; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); ApplySpellFix({ 67275 // light surge 2 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 67223; }); ApplySpellFix({ 67298 // light 3 }, [](SpellEntry* spellInfo) { //spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; spellInfo->EffectImplicitTargetA[0] = 6; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); ApplySpellFix({ 67276 // light surge 3 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 67224; }); ApplySpellFix({ 66001 // dark 0 }, [](SpellEntry* spellInfo) { //spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; spellInfo->EffectImplicitTargetA[0] = 6; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); ApplySpellFix({ 65769 // dark surge 0 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 65684; }); ApplySpellFix({ 67281 // dark 1 }, [](SpellEntry* spellInfo) { //spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; spellInfo->EffectImplicitTargetA[0] = 6; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); ApplySpellFix({ 67265 // dark surge 1 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 67176; }); ApplySpellFix({ 67282 // dark 2 }, [](SpellEntry* spellInfo) { //spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; spellInfo->EffectImplicitTargetA[0] = 6; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); ApplySpellFix({ 67266 // dark surge 2 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 67177; }); ApplySpellFix({ 67283 // dark 3 }, [](SpellEntry* spellInfo) { //spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; spellInfo->EffectImplicitTargetA[0] = 6; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); ApplySpellFix({ 67267 // dark surge 3 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 67178; }); // Trial of the Crusader, Twin Valkyr, Twin's Pact ApplySpellFix({ 65875, 67303, 67304, 67305, 65876, 67306, 67307, 67308 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); // Trial of the Crusader, Anub'arak, Emerge ApplySpellFix({ 65982 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx5 |= SPELL_ATTR5_USABLE_WHILE_STUNNED; }); // Trial of the Crusader, Anub'arak, Penetrating Cold ApplySpellFix({ 66013, 67700, 68509, 68510 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 12; // 100yd }); // Trial of the Crusader, Anub'arak, Shadow Strike ApplySpellFix({ 66134 }, [](SpellEntry* spellInfo) { spellInfo->InterruptFlags |= SPELL_INTERRUPT_FLAG_INTERRUPT; spellInfo->Effect[0] = 0; }); // Trial of the Crusader, Anub'arak, Pursuing Spikes ApplySpellFix({ 65920, 65922, 65923 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_DUMMY; //spellInfo->EffectTriggerSpell[0] = 0; }); // Trial of the Crusader, Anub'arak, Summon Scarab ApplySpellFix({ 66339 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 35; spellInfo->EffectImplicitTargetA[0] = 25; spellInfo->EffectImplicitTargetB[0] = 0; }); // Trial of the Crusader, Anub'arak, Achievements: The Traitor King ApplySpellFix({ 68186, // Anub'arak Scarab Achievement 10 68515 // Anub'arak Scarab Achievement 25 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENEMY; spellInfo->Attributes |= SPELL_ATTR0_CASTABLE_WHILE_DEAD; }); // Trial of the Crusader, Anub'arak, Spider Frenzy ApplySpellFix({ 66129 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Soul Sickness ApplySpellFix({ 69131 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PERIODIC_TRIGGER_SPELL; spellInfo->EffectAmplitude[0] = 8000; spellInfo->EffectTriggerSpell[0] = 69133; }); // Phantom Blast ApplySpellFix({ 68982, 70322 }, [](SpellEntry* spellInfo) { spellInfo->InterruptFlags |= SPELL_INTERRUPT_FLAG_INTERRUPT; }); // Empowered Blizzard ApplySpellFix({ 70131 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Ice Lance Volley ApplySpellFix({ 70464 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENTRY; spellInfo->EffectRadiusIndex[0] = 25; }); ApplySpellFix({ 70513, // Multi-Shot 59514 // Shriek of the Highborne }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CONE_ENTRY; spellInfo->EffectImplicitTargetB[0] = 0; }); // Icicle ApplySpellFix({ 69428, 69426 }, [](SpellEntry* spellInfo) { spellInfo->InterruptFlags = 0; spellInfo->AuraInterruptFlags = 0; spellInfo->ChannelInterruptFlags = 0; }); ApplySpellFix({ 70525, 70639 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; spellInfo->Effect[1] = 0; spellInfo->EffectImplicitTargetA[2] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[2] = TARGET_UNIT_SRC_AREA_ENTRY; spellInfo->EffectRadiusIndex[2] = 30; // 500yd }); // Frost Nova ApplySpellFix({ 68198 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 13; spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION; }); // Blight ApplySpellFix({ 69604, 70286 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 1; spellInfo->AttributesEx3 |= (SPELL_ATTR3_IGNORE_HIT_RESULT | SPELL_ATTR3_ONLY_TARGET_PLAYERS); }); // Chilling Wave ApplySpellFix({ 68778, 70333 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[0] = 0; }); ApplySpellFix({ 68786, 70336 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= (SPELL_ATTR3_IGNORE_HIT_RESULT | SPELL_ATTR3_ONLY_TARGET_PLAYERS); spellInfo->Effect[2] = SPELL_EFFECT_DUMMY; }); // Pursuit ApplySpellFix({ 68987 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[1] = 0; spellInfo->EffectImplicitTargetA[2] = TARGET_UNIT_CASTER; spellInfo->EffectImplicitTargetB[2] = 0; spellInfo->rangeIndex = 6; // 100yd spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); ApplySpellFix({ 69029, 70850 }, [](SpellEntry* spellInfo) { spellInfo->Effect[2] = 0; }); // Explosive Barrage ApplySpellFix({ 69263 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_MOD_STUN; }); // Overlord's Brand ApplySpellFix({ 69172 }, [](SpellEntry* spellInfo) { spellInfo->procFlags = DONE_HIT_PROC_FLAG_MASK & ~PROC_FLAG_DONE_PERIODIC; spellInfo->procChance = 100; }); // Icy Blast ApplySpellFix({ 69232 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[1] = 69238; spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); ApplySpellFix({ 69233, 69646 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); ApplySpellFix({ 69238, 69628 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; spellInfo->EffectImplicitTargetB[0] = TARGET_DEST_DYNOBJ_NONE; spellInfo->EffectImplicitTargetA[1] = TARGET_DEST_DEST; spellInfo->EffectImplicitTargetB[1] = TARGET_DEST_DYNOBJ_NONE; spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Hoarfrost ApplySpellFix({ 69246, 69245, 69645 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Devour Humanoid ApplySpellFix({ 69503 }, [](SpellEntry* spellInfo) { spellInfo->ChannelInterruptFlags |= 0; spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING; }); // Falric: Defiling Horror ApplySpellFix({ 72435, 72452 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; }); // Frostsworn General - Throw Shield ApplySpellFix({ 69222, 73076 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[2] = TARGET_UNIT_TARGET_ENEMY; }); // Halls of Reflection Clone ApplySpellFix({ 69828 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; spellInfo->Effect[2] = 0; }); // Summon Ice Wall ApplySpellFix({ 69768 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; }); ApplySpellFix({ 69767 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_TARGET_ANY; spellInfo->EffectImplicitTargetA[2] = TARGET_UNIT_TARGET_ANY; }); // Essence of the Captured ApplySpellFix({ 73035, 70719 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 13; }); // Achievement Check ApplySpellFix({ 72830 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; }); ApplySpellFix({ 70781, // Light's Hammer Teleport 70856, // Oratory of the Damned Teleport 70857, // Rampart of Skulls Teleport 70858, // Deathbringer's Rise Teleport 70859, // Upper Spire Teleport 70860, // Frozen Throne Teleport 70861 // Sindragosa's Lair Teleport }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->EffectImplicitTargetA[1] = TARGET_DEST_DB; // this target is for SPELL_EFFECT_TELEPORT_UNITS spellInfo->EffectImplicitTargetB[1] = 0; spellInfo->EffectImplicitTargetA[2] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[2] = 0; }); ApplySpellFix({ 70960, // Bone Flurry 71258 // Adrenaline Rush (Ymirjar Battle-Maiden) }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx &= ~SPELL_ATTR1_CHANNELED_2; }); // Saber Lash (Lord Marrowgar) ApplySpellFix({ 69055, 70814 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 8; // 5yd }); // Impaled (Lord Marrowgar) ApplySpellFix({ 69065 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; // remove stun so Dispersion can be used }); // Cold Flame (Lord Marrowgar) ApplySpellFix({ 72701, 72702, 72703, 72704 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; spellInfo->EffectImplicitTargetA[1] = TARGET_DEST_DEST; spellInfo->EffectImplicitTargetB[1] = 0; spellInfo->DurationIndex = 9; // 30 secs instead of 12, need him for longer, but will stop his actions after 12 secs }); ApplySpellFix({ 69138 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; spellInfo->EffectImplicitTargetA[1] = TARGET_DEST_DEST; spellInfo->DurationIndex = 9; // 30 secs instead of 12, need him for longer, but will stop his actions after 12 secs }); ApplySpellFix({ 69146, 70823, 70824, 70825 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 15; // 3yd instead of 5yd spellInfo->AttributesEx4 &= ~SPELL_ATTR4_IGNORE_RESISTANCES; }); // Dark Martyrdom (Lady Deathwhisper) ApplySpellFix({ 70897 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_DEAD; }); ApplySpellFix({ 69075, // Bone Storm (Lord Marrowgar) 70834, // Bone Storm (Lord Marrowgar) 70835, // Bone Storm (Lord Marrowgar) 70836, // Bone Storm (Lord Marrowgar) 72378, // Blood Nova (Deathbringer Saurfang) 73058, // Blood Nova (Deathbringer Saurfang) 72769, // Scent of Blood (Deathbringer Saurfang) 72385, // Boiling Blood (Deathbringer Saurfang) 72441, // Boiling Blood (Deathbringer Saurfang) 72442, // Boiling Blood (Deathbringer Saurfang) 72443, // Boiling Blood (Deathbringer Saurfang) 71160, // Plague Stench (Stinky) 71161, // Plague Stench (Stinky) 71123, // Decimate (Stinky & Precious) 71464 // Divine Surge (Sister Svalna) }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = 12; // 100yd }); // Shadow's Fate ApplySpellFix({ 71169 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); // Lock Players and Tap Chest ApplySpellFix({ 72347 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 &= ~SPELL_ATTR3_NO_INITIAL_AGGRO; }); // Award Reputation - Boss Kill ApplySpellFix({ 73843, 73844, 73845, 73846 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_50000_YARDS; }); // Death Plague (Rotting Frost Giant) ApplySpellFix({ 72864 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 0; }); // Gunship Battle, spell Below Zero ApplySpellFix({ 69705 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); // Resistant Skin (Deathbringer Saurfang adds) ApplySpellFix({ 72723 }, [](SpellEntry* spellInfo) { // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client spellInfo->Effect[2] = 0; }); // Mark of the Fallen Champion (Deathbringer Saurfang) ApplySpellFix({ 72255, 72444, 72445, 72446 }, [](SpellEntry* spellInfo) { // Patch 3.3.2 (2010-01-02): Deathbringer Saurfang will no longer gain blood power from Mark of the Fallen Champion. // prevented in script, effect needed for Prayer of Mending spellInfo->AttributesEx3 &= ~SPELL_ATTR3_CANT_TRIGGER_PROC; }); // Coldflame Jets (Traps after Saurfang) ApplySpellFix({ 70460 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 1; // 10 seconds }); ApplySpellFix({ 70461, // Coldflame Jets (Traps after Saurfang) 71289 // Dominate Mind (Lady Deathwhisper) }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Severed Essence (Val'kyr Herald) ApplySpellFix({ 71906, 71942 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[0] = 0; spellInfo->Effect[1] = 0; }); ApplySpellFix({ 71159, // Awaken Plagued Zombies (Precious) 71302 // Awaken Ymirjar Fallen (Ymirjar Deathbringer) }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 21; }); // Blood Prince Council, Invocation of Blood ApplySpellFix({ 70981, 70982, 70952 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; // clear share health aura }); // Ymirjar Frostbinder, Frozen Orb ApplySpellFix({ 71274 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = 6; }); // Ooze Flood (Rotface) ApplySpellFix({ 69783, 69797, 69799, 69802 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx |= SPELL_ATTR1_CANT_TARGET_SELF; }); // Volatile Ooze Beam Protection ApplySpellFix({ 70530 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AURA; // blizzard typo, 65 instead of 6, aura itself is defined (dummy) }); // Professor Putricide, Gaseous Bloat (Orange Ooze Channel) ApplySpellFix({ 70672, 72455, 72832, 72833 }, [](SpellEntry* spellInfo) { // copied attributes from Green Ooze Channel spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY; spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); ApplySpellFix({ 71412, // Green Ooze Summon (Professor Putricide) 71415 // Orange Ooze Summon (Professor Putricide) }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; }); ApplySpellFix({ 71621, // Create Concoction (Professor Putricide) 72850, 72851, 72852, 71893, // Guzzle Potions (Professor Putricide) 73120, 73121, 73122 }, [](SpellEntry* spellInfo) { spellInfo->CastingTimeIndex = 15; // 4 sec }); // Mutated Plague (Professor Putricide) ApplySpellFix({ 72454, 72464, 72506, 72507 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx4 |= SPELL_ATTR4_IGNORE_RESISTANCES; spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd }); // Unbound Plague (Professor Putricide) (needs target selection script) ApplySpellFix({ 70911, 72854, 72855, 72856 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ENEMY; }); // Mutated Transformation (Professor Putricide) ApplySpellFix({ 70402, 72511, 72512, 72513 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT; }); // Empowered Flare (Blood Prince Council) ApplySpellFix({ 71708, 72785, 72786, 72787 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; }); ApplySpellFix({ 71518, // Unholy Infusion Quest Credit (Professor Putricide) 72934, // Blood Infusion Quest Credit (Blood-Queen Lana'thel) 72289 // Frost Infusion Quest Credit (Sindragosa) }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // another missing radius }); // Swarming Shadows ApplySpellFix({ 71266, 72890 }, [](SpellEntry* spellInfo) { spellInfo->AreaGroupId = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel }); ApplySpellFix({ 71301, // Summon Dream Portal (Valithria Dreamwalker) 71977 // Summon Nightmare Portal (Valithria Dreamwalker) }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; spellInfo->EffectImplicitTargetB[0] = 0; }); // Column of Frost (visual marker) ApplySpellFix({ 70715 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 32; // 6 seconds (missing) }); // Mana Void (periodic aura) ApplySpellFix({ 71085 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 9; // 30 seconds (missing) }); // Summon Suppressor (needs target selection script) ApplySpellFix({ 70936 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[0] = 0; }); // Corruption ApplySpellFix({ 70602 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; }); ApplySpellFix({ 72706, // Achievement Check (Valithria Dreamwalker) 71357 // Order Whelp }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd }); // Sindragosa's Fury ApplySpellFix({ 70598 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Tail Smash (Sindragosa) ApplySpellFix({ 71077 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_CASTER_BACK; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_DEST_AREA_ENEMY; spellInfo->EffectImplicitTargetA[1] = TARGET_DEST_CASTER_BACK; spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_DEST_AREA_ENEMY; }); // Frost Bomb ApplySpellFix({ 69846 }, [](SpellEntry* spellInfo) { spellInfo->speed = 0.0f; // This spell's summon happens instantly }); // Mystic Buffet (Sindragosa) ApplySpellFix({ 70127, 72528, 72529, 72530 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = 0; // remove obsolete spell effect with no targets }); // Sindragosa, Frost Aura ApplySpellFix({ 70084, 71050, 71051, 71052 }, [](SpellEntry* spellInfo) { spellInfo->Attributes &= ~SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY; }); // Ice Lock ApplySpellFix({ 71614 }, [](SpellEntry* spellInfo) { spellInfo->Mechanic = MECHANIC_STUN; }); // Lich King, Infest ApplySpellFix({ 70541, 73779, 73780, 73781 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Lich King, Necrotic Plague ApplySpellFix({ 70337, 73912, 73913, 73914, 70338, 73785, 73786, 73787 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); ApplySpellFix({ 69099, // Ice Pulse 10n 73776, // Ice Pulse 25n 73777, // Ice Pulse 10h 73778 // Ice Pulse 25h }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT; spellInfo->AttributesEx4 &= ~SPELL_ATTR4_IGNORE_RESISTANCES; }); // Fury of Frostmourne ApplySpellFix({ 72350 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd }); ApplySpellFix({ 72351, // Fury of Frostmourne 72431, // Jump (removes Fury of Frostmourne debuff) 72429, // Mass Resurrection 73159 // Play Movie }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd }); // Raise Dead ApplySpellFix({ 72376 }, [](SpellEntry* spellInfo) { spellInfo->MaxAffectedTargets = 4; spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd }); // Jump ApplySpellFix({ 71809 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 5; // 40yd spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_10_YARDS; // 10yd spellInfo->EffectMiscValue[0] = 190; }); // Broken Frostmourne ApplySpellFix({ 72405 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd }); // Summon Shadow Trap ApplySpellFix({ 73540 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 3; // 60 seconds }); // Shadow Trap (visual) ApplySpellFix({ 73530 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 28; // 5 seconds }); // Shadow Trap ApplySpellFix({ 73529 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_10_YARDS; // 10yd }); // Shadow Trap (searcher) ApplySpellFix({ 74282 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_3_YARDS; // 3yd }); // Raging Spirit Visual ApplySpellFix({ 69198 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 13; // 50000yd spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_HIT_RESULT; }); // Defile ApplySpellFix({ 72762 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 559; // 53 seconds spellInfo->excludeCasterAuraSpell = 0; spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY; spellInfo->AttributesEx6 |= (SPELL_ATTR6_CAN_TARGET_INVISIBLE | SPELL_ATTR6_CAN_TARGET_UNTARGETABLE); }); // Defile ApplySpellFix({ 72743 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 22; // 45 seconds }); ApplySpellFix({ 72754, 73708, 73709, 73710 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd }); // Val'kyr Target Search ApplySpellFix({ 69030 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_200_YARDS; // 200yd spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY; }); // Harvest Souls ApplySpellFix({ 73654, 74295, 74296, 74297 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd spellInfo->EffectRadiusIndex[1] = EFFECT_RADIUS_50000_YARDS; // 50000yd spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_50000_YARDS; // 50000yd }); // Restore Soul ApplySpellFix({ 72595, 73650 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd }); // Kill Frostmourne Players ApplySpellFix({ 75127 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd }); // Harvest Soul ApplySpellFix({ 73655 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; }); // Destroy Soul ApplySpellFix({ 74086 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd }); // Summon Spirit Bomb ApplySpellFix({ 74302, 74342 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd spellInfo->MaxAffectedTargets = 1; }); // Summon Spirit Bomb ApplySpellFix({ 74341, 74343 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // 200yd spellInfo->MaxAffectedTargets = 3; }); // Summon Spirit Bomb ApplySpellFix({ 73579 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_25_YARDS; // 25yd }); // Trigger Vile Spirit (Inside, Heroic) ApplySpellFix({ 73582 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // 50000yd }); // Scale Aura (used during Dominate Mind from Lady Deathwhisper) ApplySpellFix({ 73261 }, [](SpellEntry* spellInfo) { spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; }); // Leap to a Random Location ApplySpellFix({ 70485 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 6; // 100yd spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_10_YARDS; spellInfo->EffectMiscValue[0] = 100; }); // Empowered Blood ApplySpellFix({ 70227, 70232 }, [](SpellEntry* spellInfo) { spellInfo->AreaGroupId = 2452; // Whole icc instead of Crimson Halls only, remove when area calculation is fixed }); ApplySpellFix({ 74509 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_20_YARDS; spellInfo->EffectRadiusIndex[EFFECT_1] = EFFECT_RADIUS_20_YARDS; }); // Rallying Shout ApplySpellFix({ 75414 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_20_YARDS; }); // Barrier Channel ApplySpellFix({ 76221 }, [](SpellEntry* spellInfo) { spellInfo->ChannelInterruptFlags &= ~(AURA_INTERRUPT_FLAG_TURNING | AURA_INTERRUPT_FLAG_MOVE); spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_UNIT_NEARBY_ENTRY; }); // Intimidating Roar ApplySpellFix({ 74384 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_100_YARDS; spellInfo->EffectRadiusIndex[EFFECT_1] = EFFECT_RADIUS_100_YARDS; }); ApplySpellFix({ 74562, // Fiery Combustion 74792 // Soul Consumption }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx |= SPELL_ATTR1_CANT_BE_REDIRECTED; }); // Combustion ApplySpellFix({ 75883, 75884 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_6_YARDS; spellInfo->EffectRadiusIndex[EFFECT_1] = EFFECT_RADIUS_6_YARDS; }); // Consumption ApplySpellFix({ 75875, 75876 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_6_YARDS; spellInfo->EffectRadiusIndex[EFFECT_1] = EFFECT_RADIUS_6_YARDS; spellInfo->EffectMechanic[EFFECT_0] = 0; spellInfo->EffectMechanic[EFFECT_1] = MECHANIC_SNARE; }); // Soul Consumption ApplySpellFix({ 74799 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_1] = EFFECT_RADIUS_12_YARDS; }); // Twilight Cutter ApplySpellFix({ 74769, 77844, 77845, 77846 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_100_YARDS; }); // Twilight Mending ApplySpellFix({ 75509 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE; spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; spellInfo->EffectRadiusIndex[EFFECT_0] = EFFECT_RADIUS_100_YARDS; spellInfo->EffectRadiusIndex[EFFECT_1] = EFFECT_RADIUS_100_YARDS; }); // Meteor Strike ApplySpellFix({ 74637 }, [](SpellEntry* spellInfo) { spellInfo->speed = 0; }); //Blazing Aura ApplySpellFix({ 75885, 75886 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx4 &= ~SPELL_ATTR4_IGNORE_RESISTANCES; }); ApplySpellFix({ 75952, //Meteor Strike 74629 //Combustion Periodic }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx4 &= ~SPELL_ATTR4_IGNORE_RESISTANCES; }); // Going Bearback ApplySpellFix({ 54897 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = SPELL_EFFECT_DUMMY; spellInfo->EffectRadiusIndex[1] = spellInfo->EffectRadiusIndex[0]; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_DEST_AREA_ENTRY; spellInfo->AttributesEx4 &= ~SPELL_ATTR4_CAN_CAST_WHILE_CASTING; }); // Still At It ApplySpellFix({ 51931, 51932, 51933 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = 38; spellInfo->EffectImplicitTargetB[0] = 0; }); // Rallying the Troops ApplySpellFix({ 47394 }, [](SpellEntry* spellInfo) { spellInfo->excludeTargetAuraSpell = 47394; }); // A Tangled Skein ApplySpellFix({ 51165, 51173 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); ApplySpellFix({ 69563, // A Cloudlet of Classy Cologne 69445, // A Perfect Puff of Perfume 69489 // Bonbon Blitz }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_CASTER; }); // Control ApplySpellFix({ 30790 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValue[1] = 0; }); // Reclusive Runemaster ApplySpellFix({ 48028 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENEMY; }); // Mastery of ApplySpellFix({ 65147 }, [](SpellEntry* spellInfo) { spellInfo->Category = 1244; spellInfo->CategoryRecoveryTime = 1500; }); // Weakness to Lightning ApplySpellFix({ 46432 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 &= ~SPELL_ATTR3_DEATH_PERSISTENT; }); // Wrangle Some Aether Rays! ApplySpellFix({ 40856 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 27; // 3000ms }); // The Black Knight's Orders ApplySpellFix({ 63163 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 52390; }); // The Warp Rifts ApplySpellFix({ 34888 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 5; // 300 secs }); // The Smallest Creatures ApplySpellFix({ 38544 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValueB[0] = 427; spellInfo->EffectImplicitTargetA[0] = 1; spellInfo->Effect[1] = 0; }); // Ridding the red rocket ApplySpellFix({ 49177 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 1; // corrects seat id (points - 1 = seatId) }); // The Iron Colossus ApplySpellFix({ 56513, 56524 }, [](SpellEntry* spellInfo) { spellInfo->RecoveryTime = (spellInfo->Id == 56524 ? 6000 : 2000); }); // Kaw the Mammoth Destroyer ApplySpellFix({ 46260 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // That's Abominable ApplySpellFix({ 59565 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValueB[0] = 1721; // controlable guardian }); // Investigate the Blue Recluse (1920) // Investigate the Alchemist Shop (1960) ApplySpellFix({ 9095 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_DUMMY; spellInfo->EffectRadiusIndex[0] = 13; }); // Dragonmaw Race: All parts ApplySpellFix({ 40890 // Oldie's Rotten Pumpkin }, [](SpellEntry* spellInfo) { spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION; spellInfo->EffectTriggerSpell[0] = 40905; spellInfo->Effect[0] = SPELL_EFFECT_TRIGGER_MISSILE; spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Trope's Slime Cannon ApplySpellFix({ 40909 }, [](SpellEntry* spellInfo) { spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION; spellInfo->EffectTriggerSpell[0] = 40905; spellInfo->Effect[0] = SPELL_EFFECT_TRIGGER_MISSILE; spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Corlok's Skull Barrage ApplySpellFix({ 40894 }, [](SpellEntry* spellInfo) { spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION; spellInfo->EffectTriggerSpell[0] = 40900; spellInfo->Effect[0] = SPELL_EFFECT_TRIGGER_MISSILE; spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Ichman's Blazing Fireball ApplySpellFix({ 40928 }, [](SpellEntry* spellInfo) { spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION; spellInfo->EffectTriggerSpell[0] = 40929; spellInfo->Effect[0] = SPELL_EFFECT_TRIGGER_MISSILE; spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Mulverick's Great Balls of Lightning ApplySpellFix({ 40930 }, [](SpellEntry* spellInfo) { spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION; spellInfo->EffectTriggerSpell[0] = 40931; spellInfo->Effect[0] = SPELL_EFFECT_TRIGGER_MISSILE; spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Sky Shatter ApplySpellFix({ 40945 }, [](SpellEntry* spellInfo) { spellInfo->Targets |= TARGET_FLAG_DEST_LOCATION; spellInfo->EffectTriggerSpell[0] = 41064; spellInfo->Effect[0] = SPELL_EFFECT_TRIGGER_MISSILE; spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; }); // Gauging the Resonant Frequency (10594) ApplySpellFix({ 37390 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValueB[0] = 181; }); // Where in the World is Hemet Nesingwary? (12521) ApplySpellFix({ 50860 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 50860; }); ApplySpellFix({ 50861 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 0; }); // Krolmir, Hammer of Storms (13010) ApplySpellFix({ 56606, 56541 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[0] = 1; }); // Blightbeasts be Damned! (12072) ApplySpellFix({ 47424 }, [](SpellEntry* spellInfo) { spellInfo->AuraInterruptFlags &= ~AURA_INTERRUPT_FLAG_NOT_ABOVEWATER; }); // Leading the Charge (13380), All Infra-Green bomber quests ApplySpellFix({ 59059 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx4 &= ~SPELL_ATTR4_CAN_CAST_WHILE_CASTING; }); // Dark Horizon (12664), Reunited (12663) ApplySpellFix({ 52190 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[EFFECT_0] = 52391 - 1; }); // The Sum is Greater than the Parts (13043) - Chained Grip ApplySpellFix({ 60540 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValue[EFFECT_0] = 300; }); // Not a Bug (13342) ApplySpellFix({ 60531 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_DEAD; }); // Frankly, It Makes No Sense... (10672) ApplySpellFix({ 37851 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); // Honor Challenge (12939) ApplySpellFix({ 21855 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; }); // Convocation at Zol'Heb (12730) ApplySpellFix({ 52956 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_DEST_AREA_ENTRY; }); // Mangletooth Quests (http://www.wowhead.com/npc=3430) ApplySpellFix({ 7764, 10767, 16610, 16612, 16618, 17013 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; spellInfo->AttributesEx5 |= SPELL_ATTR5_SKIP_CHECKCAST_LOS_CHECK; }); //Crushing the Crown ApplySpellFix({ 71024 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DYNOBJ_NONE; }); // Battle for the Undercity ApplySpellFix({ 59892 // Cyclone fall }, [](SpellEntry* spellInfo) { spellInfo->Effect[EFFECT_0] = SPELL_EFFECT_APPLY_AREA_AURA_FRIEND; spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_10_YARDS; spellInfo->AttributesEx &= ~SPELL_ATTR0_CANT_CANCEL; spellInfo->AttributesEx3 |= SPELL_ATTR3_ONLY_TARGET_PLAYERS; }); // enchant Lightweave Embroidery ApplySpellFix({ 55637 }, [](SpellEntry* spellInfo) { spellInfo->EffectMiscValue[1] = 126; }); // Magic Broom ApplySpellFix({ 47977 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; spellInfo->Effect[1] = 0; }); // Titanium Seal of Dalaran, Toss your luck ApplySpellFix({ 60476 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; }); // Mind Amplification Dish, change charm aura ApplySpellFix({ 26740 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_MOD_CHARM; }); // Persistent Shield (fixes idiocity) ApplySpellFix({ 26467 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[0] = SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE; spellInfo->EffectTriggerSpell[0] = 26470; }); // Deadly Swiftness ApplySpellFix({ 31255 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[0] = 22588; }); // Black Magic enchant ApplySpellFix({ 59630 }, [](SpellEntry* spellInfo) { spellInfo->Attributes |= SPELL_ATTR0_PASSIVE; }); // Precious's Ribbon ApplySpellFix({ 72968 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_DEATH_PERSISTENT; }); ApplySpellFix({ 71646, // Item - Bauble of True Blood 10m 71607, // Item - Bauble of True Blood 25m 71610, // Item - Althor's Abacus trigger 10m 71641 // Item - Althor's Abacus trigger 25m }, [](SpellEntry* spellInfo) { spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC; spellInfo->spellLevel = 0; }); // Drain Life - Bryntroll ApplySpellFix({ 71838, // N 71839 // H }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT; spellInfo->AttributesEx4 |= SPELL_ATTR4_IGNORE_RESISTANCES; }); // Alchemist's Stone ApplySpellFix({ 17619 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx3 |= SPELL_ATTR3_DEATH_PERSISTENT; }); // Gnomish Death Ray ApplySpellFix({ 13278, 13280 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY; }); // Stormchops ApplySpellFix({ 43730 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[1] = 1; spellInfo->EffectImplicitTargetB[1] = 0; }); // Savory Deviate Delight (transformations), allow to mount while transformed ApplySpellFix({ 8219, 8220, 8221, 8222 }, [](SpellEntry* spellInfo) { spellInfo->Attributes &= ~SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY; }); // Clamlette Magnifique ApplySpellFix({ 72623 }, [](SpellEntry* spellInfo) { spellInfo->EffectBasePoints[EFFECT_0] = spellInfo->EffectBasePoints[EFFECT_1]; }); // Compact Harvest Reaper ApplySpellFix({ 4078 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 6; // 10 minutes }); // Dragon Kite, Tuskarr Kite - Kite String ApplySpellFix({ 45192 }, [](SpellEntry* spellInfo) { spellInfo->rangeIndex = 6; // 100yd }); // Frigid Frostling, Infrigidate ApplySpellFix({ 74960 }, [](SpellEntry* spellInfo) { spellInfo->EffectRadiusIndex[EFFECT_0] = 9; // 20yd }); // Apple Trap ApplySpellFix({ 43450 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_SRC_AREA_ENEMY; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_CASTER; spellInfo->Effect[0] = SPELL_EFFECT_DUMMY; }); // Dark Iron Attack - spawn mole machine ApplySpellFix({ 43563 }, [](SpellEntry* spellInfo) { spellInfo->Effect[2] = 0; // summon GO's manually }); // Throw Mug visual ApplySpellFix({ 42300 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; }); // Dark Iron knockback Aura ApplySpellFix({ 42299 }, [](SpellEntry* spellInfo) { spellInfo->EffectApplyAuraName[1] = SPELL_AURA_DUMMY; spellInfo->EffectMiscValue[0] = 100; spellInfo->EffectBasePoints[0] = 79; }); // Chug and Chuck! ApplySpellFix({ 42436 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_SRC_CASTER; spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_SRC_AREA_ENTRY; spellInfo->MaxAffectedTargets = 0; spellInfo->excludeCasterAuraSpell = 42299; }); // Catch the Wild Wolpertinger! ApplySpellFix({ 41621 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = SPELL_EFFECT_DUMMY; }); // Brewfest quests ApplySpellFix({ 47134, 51798 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; }); // The Heart of The Storms (12998) ApplySpellFix({ 43528 }, [](SpellEntry* spellInfo) { spellInfo->DurationIndex = 18; spellInfo->EffectImplicitTargetA[0] = 25; }); // Water splash ApplySpellFix({ 42348 }, [](SpellEntry* spellInfo) { spellInfo->Effect[0] = 0; }); // Summon Lantersn ApplySpellFix({ 44255, 44231 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; spellInfo->EffectImplicitTargetB[0] = 0; }); // Throw Head Back ApplySpellFix({ 42401 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_NEARBY_ENTRY; }); // Various food ApplySpellFix({ 65418 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[2] = 65410; }); ApplySpellFix({ 65422 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[2] = 65414; }); ApplySpellFix({ 65419 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[2] = 65416; }); ApplySpellFix({ 65420 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[2] = 65412; }); ApplySpellFix({ 65421 }, [](SpellEntry* spellInfo) { spellInfo->EffectTriggerSpell[2] = 65415; }); // Stamp Out Bonfire ApplySpellFix({ 45437 }, [](SpellEntry* spellInfo) { spellInfo->Effect[1] = SPELL_EFFECT_DUMMY; spellInfo->EffectImplicitTargetA[1] = TARGET_UNIT_NEARBY_ENTRY; spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Light Bonfire (DND) ApplySpellFix({ 29831 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; }); // Infernal ApplySpellFix({ 33240 }, [](SpellEntry* spellInfo) { spellInfo->EffectImplicitTargetA[EFFECT_0] = TARGET_DEST_TARGET_ANY; spellInfo->EffectImplicitTargetA[EFFECT_1] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetA[EFFECT_2] = TARGET_UNIT_TARGET_ANY; }); // Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER ApplySpellFix({ 47476, // Deathknight - Strangulate 15487, // Priest - Silence 5211, // Druid - Bash - R1 6798, // Druid - Bash - R2 8983 // Druid - Bash - R3 }, [](SpellEntry* spellInfo) { spellInfo->AttributesEx7 |= SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER; }); // Clicking on Warlock Summoning portal should not require mana ApplySpellFix({ 61994 }, [](SpellEntry* spellInfo) { spellInfo->ManaCostPercentage = 0; }); for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) { SpellEntry* spellInfo = (SpellEntry*)sSpellStore.LookupEntry(i); if (!spellInfo) { continue; } for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) { switch (spellInfo->Effect[j]) { case SPELL_EFFECT_CHARGE: case SPELL_EFFECT_CHARGE_DEST: case SPELL_EFFECT_JUMP: case SPELL_EFFECT_JUMP_DEST: case SPELL_EFFECT_LEAP_BACK: if (!spellInfo->speed && !spellInfo->SpellFamilyName) { spellInfo->speed = SPEED_CHARGE; } break; } // Xinef: i hope this will fix the problem with not working resurrection if (spellInfo->Effect[j] == SPELL_EFFECT_SELF_RESURRECT) { spellInfo->EffectImplicitTargetA[j] = TARGET_UNIT_CASTER; } } // Xinef: Fix range for trajectories and triggered spells for (uint8 j = 0; j < 3; ++j) { if (spellInfo->rangeIndex == 1 && (spellInfo->EffectImplicitTargetA[j] == TARGET_DEST_TRAJ || spellInfo->EffectImplicitTargetB[j] == TARGET_DEST_TRAJ)) { if (SpellEntry* spellInfo2 = (SpellEntry*)sSpellStore.LookupEntry(spellInfo->EffectTriggerSpell[j])) { spellInfo2->rangeIndex = 187; // 300yd } } } if (spellInfo->activeIconID == 2158) // flight { spellInfo->Attributes |= SPELL_ATTR0_PASSIVE; } switch (spellInfo->SpellFamilyName) { case SPELLFAMILY_PALADIN: // Seals of the Pure should affect Seal of Righteousness if (spellInfo->SpellIconID == 25 && (spellInfo->Attributes & SPELL_ATTR0_PASSIVE)) spellInfo->EffectSpellClassMask[0][1] |= 0x20000000; break; case SPELLFAMILY_DEATHKNIGHT: // Icy Touch - extend FamilyFlags (unused value) for Sigil of the Frozen Conscience to use if (spellInfo->SpellIconID == 2721 && spellInfo->SpellFamilyFlags[0] & 0x2) spellInfo->SpellFamilyFlags[0] |= 0x40; break; } } // Xinef: The Veiled Sea area in outlands (Draenei zone), client blocks casting flying mounts for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i) if (AreaTableEntry* areaEntry = const_cast(sAreaTableStore.LookupEntry(i))) { if (areaEntry->ID == 3479) areaEntry->flags |= AREA_FLAG_NO_FLY_ZONE; // Xinef: Dun Morogh, Kharanos tavern, missing resting flag else if (areaEntry->ID == 2102) areaEntry->flags |= AREA_FLAG_REST_ZONE_ALLIANCE; } // Xinef: fix for something? SummonPropertiesEntry* properties = const_cast(sSummonPropertiesStore.LookupEntry(121)); properties->Type = SUMMON_TYPE_TOTEM; properties = const_cast(sSummonPropertiesStore.LookupEntry(647)); // 52893 properties->Type = SUMMON_TYPE_TOTEM; if ((properties = const_cast(sSummonPropertiesStore.LookupEntry(628)))) // Hungry Plaguehound { properties->Category = SUMMON_CATEGORY_PET; properties->Type = SUMMON_TYPE_PET; } // Correct Pet Size CreatureDisplayInfoEntry* displayEntry = const_cast(sCreatureDisplayInfoStore.LookupEntry(17028)); // Kurken displayEntry->scale = 2.5f; // Oracles and Frenzyheart faction FactionEntry* factionEntry = const_cast(sFactionStore.LookupEntry(1104)); factionEntry->ReputationFlags[0] = 0; factionEntry = const_cast(sFactionStore.LookupEntry(1105)); factionEntry->ReputationFlags[0] = 0; // Various factions, added 14, 16 to hostile mask FactionTemplateEntry* factionTemplateEntry = const_cast(sFactionTemplateStore.LookupEntry(1978)); // Warsong Offensive factionTemplateEntry->hostileMask |= 8; factionTemplateEntry = const_cast(sFactionTemplateStore.LookupEntry(1921)); // The Taunka factionTemplateEntry->hostileMask |= 8; // Remove vehicles attr, making accessories selectable VehicleSeatEntry* vse = const_cast(sVehicleSeatStore.LookupEntry(4689)); // Siege Engine, Accessory vse->m_flags &= ~VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE; vse = const_cast(sVehicleSeatStore.LookupEntry(4692)); // Siege Engine, Accessory vse->m_flags &= ~VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE; vse = const_cast(sVehicleSeatStore.LookupEntry(4693)); // Siege Engine, Accessory vse->m_flags &= ~VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE; vse = const_cast(sVehicleSeatStore.LookupEntry(3011)); // Salvaged Demolisher, Ulduar - not allow to change seats vse->m_flags &= ~VEHICLE_SEAT_FLAG_CAN_SWITCH; vse = const_cast(sVehicleSeatStore.LookupEntry(3077)); // Salvaged Demolisher Seat, Ulduar - not allow to change seats vse->m_flags &= ~VEHICLE_SEAT_FLAG_CAN_SWITCH; // pussywizard: fix z offset for some vehicles: vse = const_cast(sVehicleSeatStore.LookupEntry(6206)); // Marrowgar - Bone Spike vse->m_attachmentOffsetZ = 4.0f; vse = const_cast(sVehicleSeatStore.LookupEntry(3806)); // Mimiron - seat on VX-001 for ACU during last phase vse->m_attachmentOffsetZ = 15.0f; vse = const_cast(sVehicleSeatStore.LookupEntry(3566)); // Mimiron - Working seat vse->m_attachmentOffsetX = -3.5f; vse->m_attachmentOffsetY = 0.0f; vse = const_cast(sVehicleSeatStore.LookupEntry(3567)); // Mimiron - Working seat vse->m_attachmentOffsetX = 2.3f; vse->m_attachmentOffsetY = -2.3f; // Pilgrim's Bounty offsets vse = const_cast(sVehicleSeatStore.LookupEntry(2841)); vse->m_attachmentOffsetX += 1.65f; vse->m_attachmentOffsetY += 0.75f; vse = const_cast(sVehicleSeatStore.LookupEntry(2842)); vse->m_attachmentOffsetX += 1.6f; vse->m_attachmentOffsetY += -1.0f; vse = const_cast(sVehicleSeatStore.LookupEntry(2843)); vse->m_attachmentOffsetX += -1.2f; vse->m_attachmentOffsetY += 0.2f; vse = const_cast(sVehicleSeatStore.LookupEntry(2844)); vse->m_attachmentOffsetX += -0.1f; vse->m_attachmentOffsetY += -1.6f; vse = const_cast(sVehicleSeatStore.LookupEntry(2845)); vse->m_attachmentOffsetX += 0.0f; vse->m_attachmentOffsetY += 1.6f; // Once Bitten, Twice Shy (10 player) - Icecrown Citadel AchievementEntry* achievement = const_cast(sAchievementStore.LookupEntry(4539)); achievement->mapID = 631; // Correct map requirement (currently has Ulduar) // Ring of Valor starting Locations GraveyardStruct const* entry = sGraveyard->GetGraveyard(1364); const_cast(entry)->z += 6.0f; entry = sGraveyard->GetGraveyard(1365); const_cast(entry)->z += 6.0f; LockEntry* key = const_cast(sLockStore.LookupEntry(36)); // 3366 Opening, allows to open without proper key key->Type[2] = LOCK_KEY_NONE; sLog->outString(">> Loading spell dbc data corrections in %u ms", GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); }