Core/Spell: revamp of immunities system

This commit is contained in:
hondacrx
2017-12-26 15:07:05 -05:00
parent 2c0134ba33
commit 3da0e167e6
13 changed files with 942 additions and 662 deletions
+6
View File
@@ -858,6 +858,12 @@ namespace Game.Entities
}
public uint DealDamage(Unit victim, uint damage, CleanDamage cleanDamage = null, DamageEffectType damagetype = DamageEffectType.Direct, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal, SpellInfo spellProto = null, bool durabilityLoss = true)
{
if (victim.IsImmunedToDamage(spellProto))
{
SendSpellDamageImmune(victim, spellProto.Id, false);
return 0;
}
if (victim.IsAIEnabled)
victim.GetAI().DamageTaken(this, ref damage);
+1 -7
View File
@@ -85,7 +85,7 @@ namespace Game.Entities
//Spells
protected Dictionary<CurrentSpellTypes, Spell> m_currentSpells = new Dictionary<CurrentSpellTypes, Spell>((int)CurrentSpellTypes.Max);
Dictionary<SpellValueMod, int> CustomSpellValueMod = new Dictionary<SpellValueMod, int>();
MultiMap<SpellImmunity, SpellImmune> m_spellImmune = new MultiMap<SpellImmunity, SpellImmune>();
MultiMap<uint, uint>[] m_spellImmune = new MultiMap<uint, uint>[(int)SpellImmunity.Max];
uint[] m_interruptMask = new uint[2];
protected int m_procDeep;
bool m_AutoRepeatFirstCast;
@@ -132,12 +132,6 @@ namespace Game.Entities
ushort _meleeAnimKitId;
}
public struct SpellImmune
{
public uint spellType;
public uint spellId;
}
public class DiminishingReturn
{
public DiminishingReturn() { }
+1 -1
View File
@@ -1403,7 +1403,7 @@ namespace Game.Entities
return GetPositionZ() - offset;
}
Unit GetUnitBeingMoved()
public Unit GetUnitBeingMoved()
{
Player player = ToPlayer();
if (player)
+100 -115
View File
@@ -794,20 +794,20 @@ namespace Game.Entities
// Parry
// For spells
// Resist
public SpellMissInfo SpellHitResult(Unit victim, SpellInfo spell, bool CanReflect)
public SpellMissInfo SpellHitResult(Unit victim, SpellInfo spellInfo, bool CanReflect)
{
if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return SpellMissInfo.None;
// Check for immune
if (victim.IsImmunedToSpell(spell))
if (victim.IsImmunedToSpell(spellInfo))
return SpellMissInfo.Immune;
// All positive spells can`t miss
// @todo client not show miss log for this spells - so need find info for this in dbc and use it!
if (spell.IsPositive()
if (spellInfo.IsPositive()
&& (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell
return SpellMissInfo.None;
// Check for immune
if (victim.IsImmunedToDamage(spell))
return SpellMissInfo.Immune;
if (this == victim)
return SpellMissInfo.None;
@@ -822,22 +822,22 @@ namespace Game.Entities
int reflectchance = victim.GetTotalAuraModifier(AuraType.ReflectSpells);
var mReflectSpellsSchool = victim.GetAuraEffectsByType(AuraType.ReflectSpellsSchool);
foreach (var eff in mReflectSpellsSchool)
if (Convert.ToBoolean(eff.GetMiscValue() & (int)spell.GetSchoolMask()))
if (Convert.ToBoolean(eff.GetMiscValue() & (int)spellInfo.GetSchoolMask()))
reflectchance += eff.GetAmount();
if (reflectchance > 0 && RandomHelper.randChance(reflectchance))
return SpellMissInfo.Reflect;
}
switch (spell.DmgClass)
switch (spellInfo.DmgClass)
{
case SpellDmgClass.Ranged:
case SpellDmgClass.Melee:
return MeleeSpellHitResult(victim, spell);
return MeleeSpellHitResult(victim, spellInfo);
case SpellDmgClass.None:
return SpellMissInfo.None;
case SpellDmgClass.Magic:
return MagicSpellHitResult(victim, spell);
return MagicSpellHitResult(victim, spellInfo);
}
return SpellMissInfo.None;
}
@@ -845,11 +845,6 @@ namespace Game.Entities
// Melee based spells hit result calculations
SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo)
{
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
// resist and deflect chances
if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return SpellMissInfo.None;
WeaponAttackType attType = WeaponAttackType.BaseAttack;
// Check damage class instead of attack type to correctly handle judgements
@@ -1433,10 +1428,11 @@ namespace Game.Entities
{
Spell spell = m_currentSpells.LookupByKey(CurrentSpellTypes.Channeled);
if (spell)
if (spell.getState() != SpellState.Finished)
return spell.GetSpellInfo().HasAttribute(SpellAttr5.CanChannelWhenMoving) && spell.IsChannelActive();
if (spell.getState() != SpellState.Finished && spell.IsChannelActive())
if (!spell.GetSpellInfo().IsMoveAllowedChannel())
return false;
return false;
return true;
}
bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura)
@@ -1552,24 +1548,35 @@ namespace Game.Entities
SendEnergizeSpellLog(victim, spellId, damage, overEnergize, powerType);
}
public void ApplySpellImmune(uint spellId, SpellImmunity op, object type, bool apply)
public void ApplySpellImmune(uint spellId, SpellImmunity op, SpellSchoolMask type, bool apply)
{
ApplySpellImmune(spellId, op, (uint)type, apply);
}
public void ApplySpellImmune(uint spellId, SpellImmunity op, AuraType type, bool apply)
{
ApplySpellImmune(spellId, op, (uint)type, apply);
}
public void ApplySpellImmune(uint spellId, SpellImmunity op, SpellEffectName type, bool apply)
{
ApplySpellImmune(spellId, op, (uint)type, apply);
}
public void ApplySpellImmune(uint spellId, SpellImmunity op, uint type, bool apply)
{
if (apply)
{
m_spellImmune[op].RemoveAll(p => p.spellType == Convert.ToUInt32(type));
SpellImmune Immune = new SpellImmune();
Immune.spellId = spellId;
Immune.spellType = Convert.ToUInt32(type);
m_spellImmune.Add(op, Immune);
m_spellImmune[(int)op].Add(type, spellId);
}
else
{
foreach (var spell in m_spellImmune[op].ToList())
var bounds = m_spellImmune[(int)op].LookupByKey(type);
foreach (var spell in bounds)
{
if (spell.spellId == spellId && spell.spellType == Convert.ToUInt32(type))
if (spell == spellId)
{
m_spellImmune.Remove(op, spell);
m_spellImmune[(int)op].Remove(type, spell);
break;
}
}
@@ -1581,28 +1588,27 @@ namespace Game.Entities
return false;
// Single spell immunity.
var idList = m_spellImmune.LookupByKey(SpellImmunity.Id);
foreach (var immune in idList)
if (immune.spellType == spellInfo.Id)
return true;
var idList = m_spellImmune[(int)SpellImmunity.Id];
if (idList.ContainsKey(spellInfo.Id))
return true;
if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return false;
if (spellInfo.Dispel != 0)
uint dispel = (uint)spellInfo.Dispel;
if (dispel != 0)
{
var dispelList = m_spellImmune.LookupByKey(SpellImmunity.Dispel);
foreach (var immune in dispelList)
if (immune.spellType == (int)spellInfo.Dispel)
return true;
var dispelList = m_spellImmune[(int)SpellImmunity.Dispel];
if (dispelList.ContainsKey(dispel))
return true;
}
// Spells that don't have effectMechanics.
if (spellInfo.Mechanic != 0)
uint mechanic = (uint)spellInfo.Mechanic;
if (mechanic != 0)
{
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic);
foreach (var immune in mechanicList)
if (immune.spellType == (int)spellInfo.Mechanic)
var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
if (mechanicList.ContainsKey(mechanic))
return true;
}
@@ -1611,7 +1617,7 @@ namespace Game.Entities
{
// State/effect immunities applied by aura expect full spell immunity
// Ignore effects with mechanic, they are supposed to be checked separately
if (effect == null || !effect.IsEffect())
if (effect == null)
continue;
if (!IsImmunedToSpellEffect(spellInfo, effect.EffectIndex))
@@ -1624,13 +1630,13 @@ namespace Game.Entities
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
return true;
if (spellInfo.Id != 42292 && spellInfo.Id != 59752)
if (!spellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) && !spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
{
var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School);
foreach (var immune in schoolList)
var schoolList = m_spellImmune[(int)SpellImmunity.School];
foreach (var pair in schoolList)
{
SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(immune.spellId);
if (Convert.ToBoolean(immune.spellType & (uint)spellInfo.GetSchoolMask())
SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(pair.Value);
if (Convert.ToBoolean(pair.Key & (uint)spellInfo.GetSchoolMask())
&& !(immuneSpellInfo != null && immuneSpellInfo.IsPositive() && spellInfo.IsPositive())
&& !spellInfo.CanPierceImmuneAura(immuneSpellInfo))
return true;
@@ -1642,18 +1648,18 @@ namespace Game.Entities
public uint GetSchoolImmunityMask()
{
uint mask = 0;
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.School);
foreach (var spell in mechanicList)
mask |= spell.spellType;
var mechanicList = m_spellImmune[(int)SpellImmunity.School];
foreach (var pair in mechanicList)
mask |= pair.Key;
return mask;
}
public uint GetMechanicImmunityMask()
{
uint mask = 0;
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic);
foreach (var spell in mechanicList)
mask |= (uint)(1 << (int)spell.spellType);
var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
foreach (var pair in mechanicList)
mask |= (1u << (int)pair.Value);
return mask;
}
@@ -1668,75 +1674,76 @@ namespace Game.Entities
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
uint eff = (uint)effect.Effect;
var effectList = m_spellImmune.LookupByKey(SpellImmunity.Effect);
foreach (var immune in effectList)
if (immune.spellType == eff)
return true;
var effectList = m_spellImmune[(int)SpellImmunity.Effect];
if (effectList.ContainsKey(eff))
return true;
uint mechanic = (uint)effect.Mechanic;
if (mechanic != 0)
{
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic);
foreach (var immune in mechanicList)
if (immune.spellType == mechanic)
return true;
var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
if (mechanicList.ContainsKey(mechanic))
return true;
}
uint aura = (uint)effect.ApplyAuraName;
if (aura != 0)
if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
{
var list = m_spellImmune.LookupByKey(SpellImmunity.State);
foreach (var immune in list)
if (immune.spellType == aura)
if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return true;
// Check for immune to application of harmful magical effects
var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool);
foreach (var immune in immuneAuraApply)
if (spellInfo.Dispel == DispelType.Magic && // Magic debuff
Convert.ToBoolean(immune.GetMiscValue() & (uint)spellInfo.GetSchoolMask()) && // Check school
!spellInfo.IsPositiveEffect(index)) // Harmful
uint aura = (uint)effect.ApplyAuraName;
if (aura != 0)
{
var list = m_spellImmune[(int)SpellImmunity.State];
if (list.ContainsKey(aura))
return true;
if (!spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
{
// Check for immune to application of harmful magical effects
var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool);
foreach (var auraEffect in immuneAuraApply)
if (Convert.ToBoolean(auraEffect.GetMiscValue() & (int)spellInfo.GetSchoolMask()) && // Check school
!spellInfo.IsPositiveEffect(index)) // Harmful
return true;
}
}
}
return false;
}
public bool IsImmunedToDamage(SpellSchoolMask shoolMask)
public bool IsImmunedToDamage(SpellSchoolMask schoolMask)
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School);
var schoolList = m_spellImmune[(int)SpellImmunity.School];
foreach (var immune in schoolList)
if (Convert.ToBoolean(immune.spellType & (uint)shoolMask))
if (Convert.ToBoolean(immune.Key & (uint)schoolMask))
return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
var damageList = m_spellImmune.LookupByKey(SpellImmunity.Damage);
var damageList = m_spellImmune[(int)SpellImmunity.Damage];
foreach (var immune in damageList)
if (Convert.ToBoolean(immune.spellType & (uint)shoolMask))
if (Convert.ToBoolean(immune.Key & (uint)schoolMask))
return true;
return false;
}
public bool IsImmunedToDamage(SpellInfo spellInfo)
{
if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
if (spellInfo == null)
return false;
uint shoolMask = (uint)spellInfo.GetSchoolMask();
if (spellInfo.Id != 42292 && spellInfo.Id != 59752)
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School);
foreach (var immune in schoolList)
if (Convert.ToBoolean(immune.spellType & shoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(immune.spellId)))
return true;
}
if (spellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
return false;
uint schoolMask = (uint)spellInfo.GetSchoolMask();
// If m_immuneToSchool type contain this school type, IMMUNE damage.
var schoolList = m_spellImmune[(int)SpellImmunity.School];
foreach (var pair in schoolList)
if (Convert.ToBoolean(pair.Key & schoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(pair.Value)))
return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
var damageList = m_spellImmune.LookupByKey(SpellImmunity.Damage);
var damageList = m_spellImmune[(int)SpellImmunity.Damage];
foreach (var immune in damageList)
if (Convert.ToBoolean(immune.spellType & shoolMask))
if (Convert.ToBoolean(immune.Key & schoolMask))
return true;
return false;
@@ -2173,7 +2180,7 @@ namespace Game.Entities
bool isSpellBlocked(Unit victim, SpellInfo spellProto, WeaponAttackType attackType = WeaponAttackType.BaseAttack)
{
// These spells can't be blocked
if (spellProto != null && spellProto.HasAttribute(SpellAttr0.ImpossibleDodgeParryBlock))
if (spellProto != null && (spellProto.HasAttribute(SpellAttr0.ImpossibleDodgeParryBlock) || spellProto.HasAttribute(SpellAttr3.IgnoreHitResult)))
return false;
// Can't block when casting/controlled
@@ -2657,28 +2664,6 @@ namespace Game.Entities
return null;
}
public void ApplySpellDispelImmunity(SpellInfo spellProto, DispelType type, bool apply)
{
ApplySpellImmune(spellProto.Id, SpellImmunity.Dispel, type, apply);
if (apply && spellProto.HasAttribute(SpellAttr1.DispelAurasOnImmunity))
{
// Create dispel mask by dispel type
uint dispelMask = SpellInfo.GetDispelMask(type);
// Dispel all existing auras vs current dispel type
var auras = GetAppliedAuras();
foreach (var pair in auras)
{
SpellInfo spell = pair.Value.GetBase().GetSpellInfo();
if ((spell.GetDispelMask() & dispelMask) != 0)
{
// Dispel aura
RemoveAura(pair);
}
}
}
}
public DiminishingLevels GetDiminishing(DiminishingGroup group)
{
DiminishingReturn diminish = m_Diminishing[(int)group];
+3
View File
@@ -54,6 +54,9 @@ namespace Game.Entities
m_modAttackSpeedPct = new float[] { 1.0f, 1.0f, 1.0f };
m_deathState = DeathState.Alive;
for (byte i = 0; i < (int)SpellImmunity.Max; ++i)
m_spellImmune[i] = new MultiMap<uint, uint>();
for (byte i = 0; i < (int)UnitMods.End; ++i)
m_auraModifiersGroup[i] = new float[] { 0.0f, 100.0f, 1.0f, 0.0f, 1.0f };
+2 -2
View File
@@ -151,8 +151,8 @@ namespace Game.Entities
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.SchoolImmunity, true);
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.ModUnattackable, true);
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.SchoolAbsorb, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, Mechanics.Shield, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, Mechanics.Immune_Shield, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, (uint)Mechanics.Shield, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, (uint)Mechanics.Immune_Shield, true);
// ... Resistance, Split damage, Change stats ...
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.DamageShield, true);