Core/Spell: revamp of immunities system
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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() { }
|
||||
|
||||
@@ -1403,7 +1403,7 @@ namespace Game.Entities
|
||||
return GetPositionZ() - offset;
|
||||
}
|
||||
|
||||
Unit GetUnitBeingMoved()
|
||||
public Unit GetUnitBeingMoved()
|
||||
{
|
||||
Player player = ToPlayer();
|
||||
if (player)
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user