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:
ariel- authored and roc13x committed 2017-05-04 05:01:47 +01:00
1 parent 091100f795
commit 76349ea8ce
3 files changed
+151 -38

No files matched your search

+2 -2
View File
@@ -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());
}
}
+142 -32
View File
@@ -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()
+7 -4
View File
@@ -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;