Core/Spell: fixed SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT to actually check effects
- This commit enables stack rule 3 to be properly used to fix auras that should be active but only one providing effects, even if the spell has multiple auras Closes #19454
This commit is contained in:
1 parent
091100f795
commit
76349ea8ce
3 files changed
+151
-38
No files matched your search
@@ -4574,7 +4574,7 @@ int32 Unit::GetTotalAuraModifier(AuraType auratype, std::function<bool(AuraEffec
|
||||
{
|
||||
// Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
|
||||
// If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
|
||||
if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), aurEff->GetAmount(), sameEffectSpellGroup))
|
||||
if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), auratype, aurEff->GetAmount(), sameEffectSpellGroup))
|
||||
modifier += aurEff->GetAmount();
|
||||
}
|
||||
}
|
||||
@@ -4601,7 +4601,7 @@ float Unit::GetTotalAuraMultiplier(AuraType auratype, std::function<bool(AuraEff
|
||||
{
|
||||
// Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
|
||||
// If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
|
||||
if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), aurEff->GetAmount(), sameEffectSpellGroup))
|
||||
if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), auratype, aurEff->GetAmount(), sameEffectSpellGroup))
|
||||
AddPct(multiplier, aurEff->GetAmount());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,32 +398,34 @@ void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>&
|
||||
}
|
||||
}
|
||||
|
||||
bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int32 amount, std::map<SpellGroup, int32>& groups) const
|
||||
bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, AuraType auraType, int32 amount, std::map<SpellGroup, int32>& groups) const
|
||||
{
|
||||
uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
|
||||
SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds(spellId);
|
||||
auto spellGroupBounds = GetSpellSpellGroupMapBounds(spellId);
|
||||
// Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
|
||||
for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
|
||||
for (auto itr = spellGroupBounds.first; itr != spellGroupBounds.second; ++itr)
|
||||
{
|
||||
SpellGroup group = itr->second;
|
||||
SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(group);
|
||||
if (found != mSpellGroupStack.end())
|
||||
auto found = mSpellSameEffectStack.find(group);
|
||||
if (found != mSpellSameEffectStack.end())
|
||||
{
|
||||
if (found->second == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
|
||||
// check auraTypes
|
||||
if (!found->second.count(uint32(auraType)))
|
||||
continue;
|
||||
|
||||
// Put the highest amount in the map
|
||||
auto groupItr = groups.find(group);
|
||||
if (groupItr == groups.end())
|
||||
groups.emplace(group, amount);
|
||||
else
|
||||
{
|
||||
// Put the highest amount in the map
|
||||
if (groups.find(group) == groups.end())
|
||||
groups[group] = amount;
|
||||
else
|
||||
{
|
||||
int32 curr_amount = groups[group];
|
||||
// Take absolute value because this also counts for the highest negative aura
|
||||
if (abs(curr_amount) < abs(amount))
|
||||
groups[group] = amount;
|
||||
}
|
||||
// return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group
|
||||
return true;
|
||||
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
|
||||
@@ -1365,19 +1367,19 @@ void SpellMgr::LoadSpellGroups()
|
||||
}
|
||||
int32 spell_id = fields[1].GetInt32();
|
||||
|
||||
groups.insert(std::set<uint32>::value_type(group_id));
|
||||
mSpellGroupSpell.insert(SpellGroupSpellMap::value_type((SpellGroup)group_id, spell_id));
|
||||
groups.insert(group_id);
|
||||
mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
for (SpellGroupSpellMap::iterator itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
|
||||
for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
|
||||
{
|
||||
if (itr->second < 0)
|
||||
{
|
||||
if (groups.find(abs(itr->second)) == groups.end())
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group` does not exist", abs(itr->second));
|
||||
mSpellGroupSpell.erase(itr++);
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
@@ -1385,31 +1387,30 @@ void SpellMgr::LoadSpellGroups()
|
||||
else
|
||||
{
|
||||
SpellInfo const* spellInfo = GetSpellInfo(itr->second);
|
||||
|
||||
if (!spellInfo)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_group` does not exist", itr->second);
|
||||
mSpellGroupSpell.erase(itr++);
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else if (spellInfo->GetRank() > 1)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_group` is not the first rank of the spell.", itr->second);
|
||||
mSpellGroupSpell.erase(itr++);
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::set<uint32>::iterator groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
|
||||
for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
|
||||
{
|
||||
std::set<uint32> spells;
|
||||
GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
|
||||
|
||||
for (std::set<uint32>::iterator spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
|
||||
for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
|
||||
{
|
||||
++count;
|
||||
mSpellSpellGroup.insert(SpellSpellGroupMap::value_type(*spellItr, SpellGroup(*groupItr)));
|
||||
mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1421,6 +1422,9 @@ void SpellMgr::LoadSpellGroupStackRules()
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
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");
|
||||
@@ -1443,20 +1447,126 @@ void SpellMgr::LoadSpellGroupStackRules()
|
||||
continue;
|
||||
}
|
||||
|
||||
SpellGroupSpellMapBounds spellGroup = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
|
||||
|
||||
if (spellGroup.first == spellGroup.second)
|
||||
auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
|
||||
if (bounds.first == bounds.second)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group_stack_rules` does not exist.", group_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
mSpellGroupStack[(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)
|
||||
mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
|
||||
else
|
||||
sameEffectGroups.push_back(group_id);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u spell group stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
count = 0;
|
||||
oldMSTime = getMSTime();
|
||||
TC_LOG_INFO("server.loading", ">> Parsing SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules...");
|
||||
|
||||
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 (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (!spellInfo->Effects[i].IsAura())
|
||||
continue;
|
||||
|
||||
int32 auraName = static_cast<int32>(spellInfo->Effects[i].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)
|
||||
TC_LOG_ERROR("sql.sql", "SpellId %u listed in `spell_group` with stack rule 3 does not share aura assigned for group %u", spellId, group_id);
|
||||
}
|
||||
|
||||
mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
|
||||
++count;
|
||||
}
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Parsed %u SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellProcs()
|
||||
|
||||
@@ -295,11 +295,11 @@ enum SpellGroup
|
||||
#define SPELL_GROUP_DB_RANGE_MIN 1000
|
||||
|
||||
// spell_id, group_id
|
||||
typedef std::multimap<uint32, SpellGroup > SpellSpellGroupMap;
|
||||
typedef std::unordered_multimap<uint32, SpellGroup> SpellSpellGroupMap;
|
||||
typedef std::pair<SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator> SpellSpellGroupMapBounds;
|
||||
|
||||
// group_id, spell_id
|
||||
typedef std::multimap<SpellGroup, int32> SpellGroupSpellMap;
|
||||
typedef std::unordered_multimap<SpellGroup, int32> SpellGroupSpellMap;
|
||||
typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_iterator> SpellGroupSpellMapBounds;
|
||||
|
||||
enum SpellGroupStackRule
|
||||
@@ -312,7 +312,9 @@ enum SpellGroupStackRule
|
||||
SPELL_GROUP_STACK_RULE_MAX
|
||||
};
|
||||
|
||||
typedef std::map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
|
||||
typedef std::unordered_map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
|
||||
|
||||
typedef std::unordered_map<SpellGroup, std::unordered_set<uint32 /*auraName*/>> SameEffectStackMap;
|
||||
|
||||
struct SpellThreatEntry
|
||||
{
|
||||
@@ -606,7 +608,7 @@ class TC_GAME_API SpellMgr
|
||||
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const;
|
||||
|
||||
// Spell Group Stack Rules table
|
||||
bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int32 amount, std::map<SpellGroup, int32>& groups) const;
|
||||
bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, AuraType auraType, int32 amount, std::map<SpellGroup, int32>& groups) const;
|
||||
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
|
||||
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const;
|
||||
|
||||
@@ -699,6 +701,7 @@ class TC_GAME_API SpellMgr
|
||||
SpellSpellGroupMap mSpellSpellGroup;
|
||||
SpellGroupSpellMap mSpellGroupSpell;
|
||||
SpellGroupStackMap mSpellGroupStack;
|
||||
SameEffectStackMap mSpellSameEffectStack;
|
||||
SpellProcMap mSpellProcMap;
|
||||
SpellBonusMap mSpellBonusMap;
|
||||
SpellThreatMap mSpellThreatMap;
|
||||
|
||||
Reference in new issue
Block a user