Skip to content

Commit

Permalink
Core/Spell: fixed SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT to act…
Browse files Browse the repository at this point in the history
…ually check effects

Port From (TrinityCore/TrinityCore@52e0074)
  • Loading branch information
hondacrx committed May 13, 2020
1 parent a528aed commit d8104a0
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 27 deletions.
4 changes: 2 additions & 2 deletions Source/Game/Entities/Unit/Unit.Spells.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4366,7 +4366,7 @@ public int GetTotalAuraModifier(AuraType auratype, Func<AuraEffect, bool> predic
{
// 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 (!Global.SpellMgr.AddSameEffectStackRuleSpellGroups(aurEff.GetSpellInfo(), aurEff.GetAmount(), sameEffectSpellGroup))
if (!Global.SpellMgr.AddSameEffectStackRuleSpellGroups(aurEff.GetSpellInfo(), auratype, aurEff.GetAmount(), sameEffectSpellGroup))
modifier += aurEff.GetAmount();
}
}
Expand Down Expand Up @@ -4398,7 +4398,7 @@ public float GetTotalAuraMultiplier(AuraType auratype, Func<AuraEffect, bool> pr
{
// 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 (!Global.SpellMgr.AddSameEffectStackRuleSpellGroups(aurEff.GetSpellInfo(), aurEff.GetAmount(), sameEffectSpellGroup))
if (!Global.SpellMgr.AddSameEffectStackRuleSpellGroups(aurEff.GetSpellInfo(), auratype, aurEff.GetAmount(), sameEffectSpellGroup))
MathFunctions.AddPct(ref multiplier, aurEff.GetAmount());
}
}
Expand Down
155 changes: 130 additions & 25 deletions Source/Game/Spells/SpellManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,31 +360,32 @@ void GetSetOfSpellsInSpellGroup(SpellGroup group_id, out List<int> foundSpells,
}
}

public bool AddSameEffectStackRuleSpellGroups(SpellInfo spellInfo, int amount, Dictionary<SpellGroup, int> groups)
public bool AddSameEffectStackRuleSpellGroups(SpellInfo spellInfo, AuraType auraType, int amount, Dictionary<SpellGroup, int> groups)
{
uint spellId = spellInfo.GetFirstRankSpell().Id;
var spellGroup = GetSpellSpellGroupMapBounds(spellId);
var spellGroupList = GetSpellSpellGroupMapBounds(spellId);
// Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
foreach (var group in spellGroup)
foreach (var group in spellGroupList)
{
var found = mSpellGroupStack.FirstOrDefault(p => p.Key == group);
if (found.Key != SpellGroup.None)
var found = mSpellSameEffectStack.LookupByKey(group);
if (found != null)
{
if (found.Value == SpellGroupStackRule.ExclusiveSameEffect)
// check auraTypes
if (!found.Any(p => p == auraType))
continue;

// Put the highest amount in the map
if (!groups.ContainsKey(group))
groups.Add(group, amount);
else
{
// Put the highest amount in the map
if (groups.FirstOrDefault(p => p.Key == group).Key == SpellGroup.None)
groups.Add(group, amount);
else
{
int curr_amount = groups[group];
// Take absolute value because this also counts for the highest negative aura
if (Math.Abs(curr_amount) < Math.Abs(amount))
groups[group] = amount;
}
// return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group
return true;
int curr_amount = groups[group];
// Take absolute value because this also counts for the highest negative aura
if (Math.Abs(curr_amount) < Math.Abs(amount))
groups[group] = 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
Expand Down Expand Up @@ -1114,8 +1115,11 @@ public void LoadSpellGroupStackRules()
uint oldMSTime = Time.GetMSTime();

mSpellGroupStack.Clear(); // need for reload case
mSpellSameEffectStack.Clear();

List<SpellGroup> sameEffectGroups = new List<SpellGroup>();

// 0 1
// 0 1
SQLResult result = DB.World.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
if (result.IsEmpty())
{
Expand All @@ -1126,28 +1130,128 @@ public void LoadSpellGroupStackRules()
uint count = 0;
do
{
uint group_id = result.Read<uint>(0);
byte stack_rule = result.Read<byte>(1);
if (stack_rule >= (byte)SpellGroupStackRule.Max)
SpellGroup group_id = (SpellGroup)result.Read<uint>(0);
SpellGroupStackRule stack_rule = (SpellGroupStackRule)result.Read<byte>(1);
if (stack_rule >= SpellGroupStackRule.Max)
{
Log.outError(LogFilter.Sql, "SpellGroupStackRule {0} listed in `spell_group_stack_rules` does not exist", stack_rule);
continue;
}

var spellGroup = GetSpellGroupSpellMapBounds((SpellGroup)group_id);

var spellGroup = GetSpellGroupSpellMapBounds(group_id);
if (spellGroup == null)
{
Log.outError(LogFilter.Sql, "SpellGroup id {0} listed in `spell_group_stack_rules` does not exist", group_id);
continue;
}

mSpellGroupStack[(SpellGroup)group_id] = (SpellGroupStackRule)stack_rule;
mSpellGroupStack.Add(group_id, stack_rule);

// different container for same effect stack rules, need to check effect types
if (stack_rule == SpellGroupStackRule.ExclusiveSameEffect)
sameEffectGroups.Add(group_id);

++count;
} while (result.NextRow());

Log.outInfo(LogFilter.ServerLoading, "Loaded {0} spell group stack rules in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));

count = 0;
oldMSTime = Time.GetMSTime();
Log.outInfo(LogFilter.ServerLoading, "Parsing SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules...");

foreach (SpellGroup group_id in sameEffectGroups)
{
GetSetOfSpellsInSpellGroup(group_id, out var spellIds);

List<AuraType> auraTypes = new List<AuraType>();

// we have to 'guess' what effect this group corresponds to
{
List<AuraType> frequencyContainer = new List<AuraType>();

// only waylay for the moment (shared group)
AuraType[] SubGroups =
{
AuraType.ModMeleeHaste,
AuraType.ModMeleeRangedHaste,
AuraType.ModRangedHaste
};

foreach (uint spellId in spellIds)
{
SpellInfo spellInfo = GetSpellInfo(spellId);
foreach (SpellEffectInfo effectInfo in spellInfo.GetEffectsForDifficulty(Difficulty.None))
{
if (!effectInfo.IsAura())
continue;

AuraType auraName = effectInfo.ApplyAuraName;
if (SubGroups.Contains(auraName))
{
// count as first aura
auraName = SubGroups[0];
}

frequencyContainer.Add(auraName);
}
}

AuraType auraType = 0;
int auraTypeCount = 0;
foreach (AuraType auraName in frequencyContainer)
{
int currentCount = frequencyContainer.Count(p => p == auraName);
if (currentCount > auraTypeCount)
{
auraType = auraName;
auraTypeCount = currentCount;
}
}

if (auraType == SubGroups[0])
{
auraTypes.AddRange(SubGroups);
break;
}

if (auraTypes.Empty())
auraTypes.Add(auraType);
}

// re-check spells against guessed group
foreach (uint spellId in spellIds)
{
SpellInfo spellInfo = GetSpellInfo(spellId);

bool found = false;
while (spellInfo != null)
{
foreach (AuraType auraType in auraTypes)
{
if (spellInfo.HasAura(Difficulty.None, auraType))
{
found = true;
break;
}
}

if (found)
break;

spellInfo = spellInfo.GetNextRankSpell();
}

// not found either, log error
if (!found)
Log.outError(LogFilter.Sql, $"SpellId {spellId} listed in `spell_group` with stack rule 3 does not share aura assigned for group {group_id}");
}

mSpellSameEffectStack[group_id] = auraTypes;
++count;
}

Log.outInfo(LogFilter.ServerLoading, $"Parsed {count} SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
}

public void LoadSpellProcs()
Expand Down Expand Up @@ -3411,6 +3515,7 @@ public BattlePetSpeciesRecord GetBattlePetSpecies(uint spellId)
MultiMap<uint, SpellGroup> mSpellSpellGroup = new MultiMap<uint, SpellGroup>();
MultiMap<SpellGroup, int> mSpellGroupSpell = new MultiMap<SpellGroup, int>();
Dictionary<SpellGroup, SpellGroupStackRule> mSpellGroupStack = new Dictionary<SpellGroup, SpellGroupStackRule>();
MultiMap<SpellGroup, AuraType> mSpellSameEffectStack = new MultiMap<SpellGroup, AuraType>();
Dictionary<uint, SpellProcEntry> mSpellProcMap = new Dictionary<uint, SpellProcEntry>();
Dictionary<uint, SpellThreatEntry> mSpellThreatMap = new Dictionary<uint, SpellThreatEntry>();
Dictionary<uint, PetAura> mSpellPetAuraMap = new Dictionary<uint, PetAura>();
Expand Down

0 comments on commit d8104a0

Please sign in to comment.