aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2017-04-14 03:47:23 -0300
committerariel- <ariel-@users.noreply.github.com>2017-04-14 03:47:23 -0300
commit9900899dd9d7f685a1c862bc75e7614e3f0a3ce6 (patch)
tree17bd722afe1a74b95d4a5173346e50495a32e61f /src
parent912351febd43043798746a2f5bd46595ffea467f (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp4
-rw-r--r--src/server/game/Spells/SpellMgr.cpp174
-rw-r--r--src/server/game/Spells/SpellMgr.h11
3 files changed, 151 insertions, 38 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 593b82f5316..c207ed57554 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -4843,7 +4843,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();
}
}
@@ -4870,7 +4870,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());
}
}
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 0de0e819dcf..d1324088f49 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -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
@@ -1315,19 +1317,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;
@@ -1335,31 +1337,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));
}
}
@@ -1371,6 +1372,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");
@@ -1393,20 +1397,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()
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 30559cc0023..f649668e996 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -304,11 +304,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
@@ -321,7 +321,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
{
@@ -613,7 +615,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;
@@ -706,6 +708,7 @@ class TC_GAME_API SpellMgr
SpellSpellGroupMap mSpellSpellGroup;
SpellGroupSpellMap mSpellGroupSpell;
SpellGroupStackMap mSpellGroupStack;
+ SameEffectStackMap mSpellSameEffectStack;
SpellProcMap mSpellProcMap;
SpellBonusMap mSpellBonusMap;
SpellThreatMap mSpellThreatMap;