mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-28 22:45:55 +00:00
fix(Core/Spells): Implement TrinityCore spell_group and spell_group_stack_rules (#23346)
Co-authored-by: treeston <treeston.mmoc@gmail.com> Co-authored-by: Trisjdc <trisjdc@gmail.com> Co-authored-by: QAston <none@none> Co-authored-by: ariel- <ariel-@users.noreply.github.com> Co-authored-by: Shauren <shauren.trinity@gmail.com> Co-authored-by: Jelle Meeus <sogladev@gmail.com>
This commit is contained in:
@@ -18,12 +18,9 @@
|
||||
#include "SpellMgr.h"
|
||||
#include "BattlefieldMgr.h"
|
||||
#include "BattlegroundIC.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "Chat.h"
|
||||
#include "DBCStores.h"
|
||||
#include "GameGraveyard.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "MapMgr.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
@@ -648,82 +645,143 @@ SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, Spe
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SpellGroupStackFlags SpellMgr::GetGroupStackFlags(uint32 groupid) const
|
||||
SpellSpellGroupMapBounds SpellMgr::GetSpellSpellGroupMapBounds(uint32 spell_id) const
|
||||
{
|
||||
SpellGroupStackMap::const_iterator itr = mSpellGroupStackMap.find(groupid);
|
||||
if (itr != mSpellGroupStackMap.end())
|
||||
spell_id = GetFirstSpellInChain(spell_id);
|
||||
return mSpellSpellGroup.equal_range(spell_id);
|
||||
}
|
||||
|
||||
bool SpellMgr::IsSpellMemberOfSpellGroup(uint32 spell_id, SpellGroup group_id) const
|
||||
{
|
||||
SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds(spell_id);
|
||||
for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
|
||||
{
|
||||
if (itr->second == group_id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellGroupSpellMapBounds SpellMgr::GetSpellGroupSpellMapBounds(SpellGroup group_id) const
|
||||
{
|
||||
return mSpellGroupSpell.equal_range(group_id);
|
||||
}
|
||||
|
||||
void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const
|
||||
{
|
||||
std::set<SpellGroup> usedGroups;
|
||||
GetSetOfSpellsInSpellGroup(group_id, foundSpells, usedGroups);
|
||||
}
|
||||
|
||||
void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const
|
||||
{
|
||||
if (usedGroups.find(group_id) != usedGroups.end())
|
||||
return;
|
||||
usedGroups.insert(group_id);
|
||||
|
||||
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(group_id);
|
||||
for (SpellGroupSpellMap::const_iterator itr = groupSpell.first; itr != groupSpell.second; ++itr)
|
||||
{
|
||||
if (itr->second < 0)
|
||||
{
|
||||
SpellGroup currGroup = (SpellGroup)abs(itr->second);
|
||||
GetSetOfSpellsInSpellGroup(currGroup, foundSpells, usedGroups);
|
||||
}
|
||||
else
|
||||
{
|
||||
foundSpells.insert(itr->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const
|
||||
{
|
||||
uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
|
||||
auto spellGroupBounds = GetSpellSpellGroupMapBounds(spellId);
|
||||
// Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
|
||||
for (auto itr = spellGroupBounds.first; itr != spellGroupBounds.second; ++itr)
|
||||
{
|
||||
SpellGroup group = itr->second;
|
||||
auto found = mSpellSameEffectStack.find(group);
|
||||
if (found != mSpellSameEffectStack.end())
|
||||
{
|
||||
// check auraTypes
|
||||
if (!found->second.count(auraType))
|
||||
continue;
|
||||
|
||||
// Put the highest amount in the map
|
||||
auto groupItr = groups.find(group);
|
||||
if (groupItr == groups.end())
|
||||
groups.emplace(group, amount);
|
||||
else
|
||||
{
|
||||
int32 curr_amount = groups[group];
|
||||
// Take absolute value because this also counts for the highest negative aura
|
||||
if (std::abs(curr_amount) < std::abs(amount))
|
||||
groupItr->second = amount;
|
||||
}
|
||||
// return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group per auraType
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const
|
||||
{
|
||||
ASSERT(spellInfo1);
|
||||
ASSERT(spellInfo2);
|
||||
|
||||
uint32 spell_id1 = spellInfo1->GetFirstRankSpell()->Id;
|
||||
uint32 spell_id2 = spellInfo2->GetFirstRankSpell()->Id;
|
||||
|
||||
// find SpellGroups which are common for both spells
|
||||
SpellSpellGroupMapBounds spellGroup1 = GetSpellSpellGroupMapBounds(spell_id1);
|
||||
std::set<SpellGroup> groups;
|
||||
for (SpellSpellGroupMap::const_iterator itr = spellGroup1.first; itr != spellGroup1.second; ++itr)
|
||||
{
|
||||
if (IsSpellMemberOfSpellGroup(spell_id2, itr->second))
|
||||
{
|
||||
bool add = true;
|
||||
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(itr->second);
|
||||
for (SpellGroupSpellMap::const_iterator itr2 = groupSpell.first; itr2 != groupSpell.second; ++itr2)
|
||||
{
|
||||
if (itr2->second < 0)
|
||||
{
|
||||
SpellGroup currGroup = (SpellGroup)abs(itr2->second);
|
||||
if (IsSpellMemberOfSpellGroup(spell_id1, currGroup) && IsSpellMemberOfSpellGroup(spell_id2, currGroup))
|
||||
{
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
groups.insert(itr->second);
|
||||
}
|
||||
}
|
||||
|
||||
SpellGroupStackRule rule = SPELL_GROUP_STACK_RULE_DEFAULT;
|
||||
|
||||
for (std::set<SpellGroup>::iterator itr = groups.begin(); itr!= groups.end(); ++itr)
|
||||
{
|
||||
SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(*itr);
|
||||
if (found != mSpellGroupStack.end())
|
||||
rule = found->second;
|
||||
if (rule)
|
||||
break;
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
|
||||
SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
|
||||
{
|
||||
SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group);
|
||||
if (itr != mSpellGroupStack.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;
|
||||
|
||||
uint32 groupId = GetSpellGroup(spellid_1);
|
||||
|
||||
SpellGroupSpecialFlags flag1 = GetSpellGroupSpecialFlags(spellid_1);
|
||||
|
||||
// xinef: dunno why i added this
|
||||
if (spellid_1 == spellid_2 && remove && !areaAura)
|
||||
{
|
||||
if (flag1 & SPELL_GROUP_SPECIAL_FLAG_SAME_SPELL_CHECK)
|
||||
{
|
||||
return SPELL_GROUP_STACK_FLAG_EXCLUSIVE;
|
||||
}
|
||||
|
||||
return SPELL_GROUP_STACK_FLAG_NONE;
|
||||
}
|
||||
|
||||
if (groupId > 0 && groupId == GetSpellGroup(spellid_2))
|
||||
{
|
||||
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<uint32>& 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
|
||||
return SPELL_GROUP_STACK_RULE_DEFAULT;
|
||||
}
|
||||
|
||||
SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
|
||||
@@ -1627,10 +1685,11 @@ void SpellMgr::LoadSpellGroups()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
mSpellGroupMap.clear(); // need for reload case
|
||||
mSpellSpellGroup.clear(); // need for reload case
|
||||
mSpellGroupSpell.clear();
|
||||
|
||||
// 0 1 2
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, spell_id, special_flag FROM spell_group");
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, spell_id FROM spell_group");
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 spell group definitions. DB table `spell_group` is empty.");
|
||||
@@ -1638,48 +1697,68 @@ void SpellMgr::LoadSpellGroups()
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<uint32> groups;
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 group_id = fields[0].Get<uint32>();
|
||||
int32 spell_id = fields[1].Get<uint32>();
|
||||
SpellGroupSpecialFlags specialFlag = (SpellGroupSpecialFlags)fields[2].Get<uint32>();
|
||||
SpellInfo const* spellInfo = GetSpellInfo(spell_id);
|
||||
|
||||
if (!spellInfo)
|
||||
if (group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` does not exist", spell_id);
|
||||
continue;
|
||||
}
|
||||
else if (spellInfo->GetRank() > 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` is not first rank of spell", spell_id);
|
||||
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` is in core range, but is not defined in core!", group_id);
|
||||
continue;
|
||||
}
|
||||
int32 spell_id = fields[1].Get<int32>();
|
||||
|
||||
if (mSpellGroupMap.find(spell_id) != mSpellGroupMap.end())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has more than one group", spell_id);
|
||||
continue;
|
||||
}
|
||||
groups.insert(group_id);
|
||||
mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
|
||||
|
||||
if (specialFlag >= SPELL_GROUP_SPECIAL_FLAG_MAX)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} 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());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Spell Group Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
|
||||
{
|
||||
if (itr->second < 0)
|
||||
{
|
||||
if (groups.find(abs(itr->second)) == groups.end())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` does not exist", abs(itr->second));
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellInfo const* spellInfo = GetSpellInfo(itr->second);
|
||||
if (!spellInfo)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` does not exist", itr->second);
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else if (spellInfo->GetRank() > 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` is not first rank of spell.", itr->second);
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
|
||||
{
|
||||
std::set<uint32> spells;
|
||||
GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
|
||||
|
||||
for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
|
||||
{
|
||||
++count;
|
||||
mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} spell group Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
@@ -1687,7 +1766,10 @@ void SpellMgr::LoadSpellGroupStackRules()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
mSpellGroupStackMap.clear(); // need for reload case
|
||||
mSpellGroupStack.clear(); // need for reload case
|
||||
mSpellSameEffectStack.clear();
|
||||
|
||||
std::vector<uint32> sameEffectGroups;
|
||||
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
|
||||
@@ -1705,32 +1787,132 @@ void SpellMgr::LoadSpellGroupStackRules()
|
||||
|
||||
uint32 group_id = fields[0].Get<uint32>();
|
||||
uint8 stack_rule = fields[1].Get<int8>();
|
||||
if (stack_rule >= SPELL_GROUP_STACK_FLAG_MAX)
|
||||
if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist", stack_rule);
|
||||
LOG_ERROR("sql.sql", "SpellGroupStackRule {} 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)
|
||||
auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
|
||||
if (bounds.first == bounds.second)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist", group_id);
|
||||
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist.", group_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
mSpellGroupStackMap[group_id] = (SpellGroupStackFlags)stack_rule;
|
||||
mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
|
||||
|
||||
// different container for same effect stack rules, need to check effect types
|
||||
if (stack_rule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
|
||||
sameEffectGroups.push_back(group_id);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Spell Group Stack Rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", ">> Loaded {} spell group stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
|
||||
count = 0;
|
||||
oldMSTime = getMSTime();
|
||||
|
||||
for (uint32 group_id : sameEffectGroups)
|
||||
{
|
||||
std::set<uint32> spellIds;
|
||||
GetSetOfSpellsInSpellGroup(SpellGroup(group_id), spellIds);
|
||||
|
||||
std::unordered_set<uint32> auraTypes;
|
||||
|
||||
// we have to 'guess' what effect this group corresponds to
|
||||
{
|
||||
std::unordered_multiset<uint32 /*auraName*/> frequencyContainer;
|
||||
|
||||
// only waylay for the moment (shared group)
|
||||
std::vector<std::vector<uint32 /*auraName*/>> const SubGroups =
|
||||
{
|
||||
{ SPELL_AURA_MOD_MELEE_HASTE, SPELL_AURA_MOD_MELEE_RANGED_HASTE, SPELL_AURA_MOD_RANGED_HASTE }
|
||||
};
|
||||
|
||||
for (uint32 spellId : spellIds)
|
||||
{
|
||||
SpellInfo const* spellInfo = AssertSpellInfo(spellId);
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
{
|
||||
if (!spellEffectInfo.IsAura())
|
||||
continue;
|
||||
|
||||
uint32 auraName = spellEffectInfo.ApplyAuraName;
|
||||
for (std::vector<uint32> const& subGroup : SubGroups)
|
||||
{
|
||||
if (std::find(subGroup.begin(), subGroup.end(), auraName) != subGroup.end())
|
||||
{
|
||||
// count as first aura
|
||||
auraName = subGroup.front();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frequencyContainer.insert(auraName);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 auraType = 0;
|
||||
size_t auraTypeCount = 0;
|
||||
for (uint32 auraName : frequencyContainer)
|
||||
{
|
||||
size_t currentCount = frequencyContainer.count(auraName);
|
||||
if (currentCount > auraTypeCount)
|
||||
{
|
||||
auraType = auraName;
|
||||
auraTypeCount = currentCount;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<uint32> const& subGroup : SubGroups)
|
||||
{
|
||||
if (auraType == subGroup.front())
|
||||
{
|
||||
auraTypes.insert(subGroup.begin(), subGroup.end());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (auraTypes.empty())
|
||||
auraTypes.insert(auraType);
|
||||
}
|
||||
|
||||
// re-check spells against guessed group
|
||||
for (uint32 spellId : spellIds)
|
||||
{
|
||||
SpellInfo const* spellInfo = AssertSpellInfo(spellId);
|
||||
|
||||
bool found = false;
|
||||
while (spellInfo)
|
||||
{
|
||||
for (uint32 auraType : auraTypes)
|
||||
{
|
||||
if (spellInfo->HasAura(AuraType(auraType)))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
break;
|
||||
|
||||
spellInfo = spellInfo->GetNextRankSpell();
|
||||
}
|
||||
|
||||
// not found either, log error
|
||||
if (!found)
|
||||
LOG_ERROR("sql.sql", "SpellId {} listed in `spell_group` with stack rule 3 does not share aura assigned for group {}", spellId, group_id);
|
||||
}
|
||||
|
||||
mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
|
||||
++count;
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
@@ -2920,6 +3102,8 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
|
||||
case SPELL_AURA_WATER_BREATHING:
|
||||
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (spellInfo->Effects[j].ApplyAuraName)
|
||||
@@ -3494,6 +3678,9 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
|
||||
if (triggerSpell->AttributesCu & SPELL_ATTR0_CU_BINARY_SPELL)
|
||||
allNonBinary = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user