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
@@ -302,6 +302,7 @@ namespace Framework.Constants
Sapped = 30, Sapped = 30,
Enraged = 31, Enraged = 31,
Wounded = 32, Wounded = 32,
Max = 33,
ImmuneToMovementImpairmentAndLossControlMask = ((1 << Charm) | (1 << Disoriented) | ImmuneToMovementImpairmentAndLossControlMask = ((1 << Charm) | (1 << Disoriented) |
(1 << Fear) | (1 << Root) | (1 << Sleep) | (1 << Snare) | (1 << Stun) | (1 << Fear) | (1 << Root) | (1 << Sleep) | (1 << Snare) | (1 << Stun) |
@@ -1370,9 +1371,9 @@ namespace Framework.Constants
IsArcaneConcentration = 0x800000, // 23 Only Mage Arcane Concentration Have This Flag IsArcaneConcentration = 0x800000, // 23 Only Mage Arcane Concentration Have This Flag
Unk24 = 0x1000000, // 24 Unk24 = 0x1000000, // 24
Unk25 = 0x2000000, // 25 Unk25 = 0x2000000, // 25
Unk26 = 0x4000000, // 26 Unaffected By School Immunity UnaffectedByAuraSchoolImmune = 0x4000000, // 26 Unaffected By School Immunity
Unk27 = 0x8000000, // 27 Unk27 = 0x8000000, // 27
Unk28 = 0x10000000, // 28 IgnoreItemCheck = 0x10000000, // 28 Spell is cast without checking item requirements (charges/reagents/totem)
CantCrit = 0x20000000, // 29 Spell Can'T Crit CantCrit = 0x20000000, // 29 Spell Can'T Crit
TriggeredCanTriggerProc = 0x40000000, // 30 Spell Can Trigger Even If Triggered TriggeredCanTriggerProc = 0x40000000, // 30 Spell Can Trigger Even If Triggered
FoodBuff = 0x80000000 // 31 Food Or Drink Buff (Like Well Fed) FoodBuff = 0x80000000 // 31 Food Or Drink Buff (Like Well Fed)
@@ -1539,7 +1540,7 @@ namespace Framework.Constants
Unk17 = 0x20000, // 17 Only 27965 (Suicide) Spell. Unk17 = 0x20000, // 17 Only 27965 (Suicide) Spell.
HasChargeEffect = 0x40000, // 18 Only Spells That Have Charge Among Effects. HasChargeEffect = 0x40000, // 18 Only Spells That Have Charge Among Effects.
ZoneTeleport = 0x80000, // 19 Teleports To Specific Zones. ZoneTeleport = 0x80000, // 19 Teleports To Specific Zones.
Unk20 = 0x100000, // 20 Blink, Divine Shield, Ice Block UsableInStunFearConfusion = 0x100000, // 20 Blink, Divine Shield, Ice Block
Unk21 = 0x200000, // 21 Not Set Unk21 = 0x200000, // 21 Not Set
Unk22 = 0x400000, // 22 Unk22 = 0x400000, // 22
Unk23 = 0x800000, // 23 Motivate, Mutilate, Shattering Throw Unk23 = 0x800000, // 23 Motivate, Mutilate, Shattering Throw
+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) 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) if (victim.IsAIEnabled)
victim.GetAI().DamageTaken(this, ref damage); victim.GetAI().DamageTaken(this, ref damage);
+1 -7
View File
@@ -85,7 +85,7 @@ namespace Game.Entities
//Spells //Spells
protected Dictionary<CurrentSpellTypes, Spell> m_currentSpells = new Dictionary<CurrentSpellTypes, Spell>((int)CurrentSpellTypes.Max); protected Dictionary<CurrentSpellTypes, Spell> m_currentSpells = new Dictionary<CurrentSpellTypes, Spell>((int)CurrentSpellTypes.Max);
Dictionary<SpellValueMod, int> CustomSpellValueMod = new Dictionary<SpellValueMod, int>(); 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]; uint[] m_interruptMask = new uint[2];
protected int m_procDeep; protected int m_procDeep;
bool m_AutoRepeatFirstCast; bool m_AutoRepeatFirstCast;
@@ -132,12 +132,6 @@ namespace Game.Entities
ushort _meleeAnimKitId; ushort _meleeAnimKitId;
} }
public struct SpellImmune
{
public uint spellType;
public uint spellId;
}
public class DiminishingReturn public class DiminishingReturn
{ {
public DiminishingReturn() { } public DiminishingReturn() { }
+1 -1
View File
@@ -1403,7 +1403,7 @@ namespace Game.Entities
return GetPositionZ() - offset; return GetPositionZ() - offset;
} }
Unit GetUnitBeingMoved() public Unit GetUnitBeingMoved()
{ {
Player player = ToPlayer(); Player player = ToPlayer();
if (player) if (player)
+100 -115
View File
@@ -794,20 +794,20 @@ namespace Game.Entities
// Parry // Parry
// For spells // For spells
// Resist // 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 // Check for immune
if (victim.IsImmunedToSpell(spell)) if (victim.IsImmunedToSpell(spellInfo))
return SpellMissInfo.Immune; return SpellMissInfo.Immune;
// All positive spells can`t miss // 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! // @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 && (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell
return SpellMissInfo.None; return SpellMissInfo.None;
// Check for immune
if (victim.IsImmunedToDamage(spell))
return SpellMissInfo.Immune;
if (this == victim) if (this == victim)
return SpellMissInfo.None; return SpellMissInfo.None;
@@ -822,22 +822,22 @@ namespace Game.Entities
int reflectchance = victim.GetTotalAuraModifier(AuraType.ReflectSpells); int reflectchance = victim.GetTotalAuraModifier(AuraType.ReflectSpells);
var mReflectSpellsSchool = victim.GetAuraEffectsByType(AuraType.ReflectSpellsSchool); var mReflectSpellsSchool = victim.GetAuraEffectsByType(AuraType.ReflectSpellsSchool);
foreach (var eff in mReflectSpellsSchool) foreach (var eff in mReflectSpellsSchool)
if (Convert.ToBoolean(eff.GetMiscValue() & (int)spell.GetSchoolMask())) if (Convert.ToBoolean(eff.GetMiscValue() & (int)spellInfo.GetSchoolMask()))
reflectchance += eff.GetAmount(); reflectchance += eff.GetAmount();
if (reflectchance > 0 && RandomHelper.randChance(reflectchance)) if (reflectchance > 0 && RandomHelper.randChance(reflectchance))
return SpellMissInfo.Reflect; return SpellMissInfo.Reflect;
} }
switch (spell.DmgClass) switch (spellInfo.DmgClass)
{ {
case SpellDmgClass.Ranged: case SpellDmgClass.Ranged:
case SpellDmgClass.Melee: case SpellDmgClass.Melee:
return MeleeSpellHitResult(victim, spell); return MeleeSpellHitResult(victim, spellInfo);
case SpellDmgClass.None: case SpellDmgClass.None:
return SpellMissInfo.None; return SpellMissInfo.None;
case SpellDmgClass.Magic: case SpellDmgClass.Magic:
return MagicSpellHitResult(victim, spell); return MagicSpellHitResult(victim, spellInfo);
} }
return SpellMissInfo.None; return SpellMissInfo.None;
} }
@@ -845,11 +845,6 @@ namespace Game.Entities
// Melee based spells hit result calculations // Melee based spells hit result calculations
SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo) 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; WeaponAttackType attType = WeaponAttackType.BaseAttack;
// Check damage class instead of attack type to correctly handle judgements // 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); Spell spell = m_currentSpells.LookupByKey(CurrentSpellTypes.Channeled);
if (spell) if (spell)
if (spell.getState() != SpellState.Finished) if (spell.getState() != SpellState.Finished && spell.IsChannelActive())
return spell.GetSpellInfo().HasAttribute(SpellAttr5.CanChannelWhenMoving) && spell.IsChannelActive(); if (!spell.GetSpellInfo().IsMoveAllowedChannel())
return false;
return false; return true;
} }
bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura) bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura)
@@ -1552,24 +1548,35 @@ namespace Game.Entities
SendEnergizeSpellLog(victim, spellId, damage, overEnergize, powerType); 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) if (apply)
{ {
m_spellImmune[op].RemoveAll(p => p.spellType == Convert.ToUInt32(type)); m_spellImmune[(int)op].Add(type, spellId);
SpellImmune Immune = new SpellImmune();
Immune.spellId = spellId;
Immune.spellType = Convert.ToUInt32(type);
m_spellImmune.Add(op, Immune);
} }
else 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; break;
} }
} }
@@ -1581,28 +1588,27 @@ namespace Game.Entities
return false; return false;
// Single spell immunity. // Single spell immunity.
var idList = m_spellImmune.LookupByKey(SpellImmunity.Id); var idList = m_spellImmune[(int)SpellImmunity.Id];
foreach (var immune in idList) if (idList.ContainsKey(spellInfo.Id))
if (immune.spellType == spellInfo.Id) return true;
return true;
if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return false; return false;
if (spellInfo.Dispel != 0) uint dispel = (uint)spellInfo.Dispel;
if (dispel != 0)
{ {
var dispelList = m_spellImmune.LookupByKey(SpellImmunity.Dispel); var dispelList = m_spellImmune[(int)SpellImmunity.Dispel];
foreach (var immune in dispelList) if (dispelList.ContainsKey(dispel))
if (immune.spellType == (int)spellInfo.Dispel) return true;
return true;
} }
// Spells that don't have effectMechanics. // 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); var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
foreach (var immune in mechanicList) if (mechanicList.ContainsKey(mechanic))
if (immune.spellType == (int)spellInfo.Mechanic)
return true; return true;
} }
@@ -1611,7 +1617,7 @@ namespace Game.Entities
{ {
// State/effect immunities applied by aura expect full spell immunity // State/effect immunities applied by aura expect full spell immunity
// Ignore effects with mechanic, they are supposed to be checked separately // Ignore effects with mechanic, they are supposed to be checked separately
if (effect == null || !effect.IsEffect()) if (effect == null)
continue; continue;
if (!IsImmunedToSpellEffect(spellInfo, effect.EffectIndex)) 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. if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
return true; 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); var schoolList = m_spellImmune[(int)SpellImmunity.School];
foreach (var immune in schoolList) foreach (var pair in schoolList)
{ {
SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(immune.spellId); SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(pair.Value);
if (Convert.ToBoolean(immune.spellType & (uint)spellInfo.GetSchoolMask()) if (Convert.ToBoolean(pair.Key & (uint)spellInfo.GetSchoolMask())
&& !(immuneSpellInfo != null && immuneSpellInfo.IsPositive() && spellInfo.IsPositive()) && !(immuneSpellInfo != null && immuneSpellInfo.IsPositive() && spellInfo.IsPositive())
&& !spellInfo.CanPierceImmuneAura(immuneSpellInfo)) && !spellInfo.CanPierceImmuneAura(immuneSpellInfo))
return true; return true;
@@ -1642,18 +1648,18 @@ namespace Game.Entities
public uint GetSchoolImmunityMask() public uint GetSchoolImmunityMask()
{ {
uint mask = 0; uint mask = 0;
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.School); var mechanicList = m_spellImmune[(int)SpellImmunity.School];
foreach (var spell in mechanicList) foreach (var pair in mechanicList)
mask |= spell.spellType; mask |= pair.Key;
return mask; return mask;
} }
public uint GetMechanicImmunityMask() public uint GetMechanicImmunityMask()
{ {
uint mask = 0; uint mask = 0;
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic); var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
foreach (var spell in mechanicList) foreach (var pair in mechanicList)
mask |= (uint)(1 << (int)spell.spellType); mask |= (1u << (int)pair.Value);
return mask; return mask;
} }
@@ -1668,75 +1674,76 @@ namespace Game.Entities
// If m_immuneToEffect type contain this effect type, IMMUNE effect. // If m_immuneToEffect type contain this effect type, IMMUNE effect.
uint eff = (uint)effect.Effect; uint eff = (uint)effect.Effect;
var effectList = m_spellImmune.LookupByKey(SpellImmunity.Effect); var effectList = m_spellImmune[(int)SpellImmunity.Effect];
foreach (var immune in effectList) if (effectList.ContainsKey(eff))
if (immune.spellType == eff) return true;
return true;
uint mechanic = (uint)effect.Mechanic; uint mechanic = (uint)effect.Mechanic;
if (mechanic != 0) if (mechanic != 0)
{ {
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic); var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
foreach (var immune in mechanicList) if (mechanicList.ContainsKey(mechanic))
if (immune.spellType == mechanic) return true;
return true;
} }
uint aura = (uint)effect.ApplyAuraName; if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
if (aura != 0)
{ {
var list = m_spellImmune.LookupByKey(SpellImmunity.State); uint aura = (uint)effect.ApplyAuraName;
foreach (var immune in list) if (aura != 0)
if (immune.spellType == aura) {
if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) var list = m_spellImmune[(int)SpellImmunity.State];
return true; if (list.ContainsKey(aura))
// 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
return true; 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; return false;
} }
public bool IsImmunedToDamage(SpellSchoolMask shoolMask) public bool IsImmunedToDamage(SpellSchoolMask schoolMask)
{ {
// If m_immuneToSchool type contain this school type, IMMUNE damage. // 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) foreach (var immune in schoolList)
if (Convert.ToBoolean(immune.spellType & (uint)shoolMask)) if (Convert.ToBoolean(immune.Key & (uint)schoolMask))
return true; return true;
// If m_immuneToDamage type contain magic, IMMUNE damage. // 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) foreach (var immune in damageList)
if (Convert.ToBoolean(immune.spellType & (uint)shoolMask)) if (Convert.ToBoolean(immune.Key & (uint)schoolMask))
return true; return true;
return false; return false;
} }
public bool IsImmunedToDamage(SpellInfo spellInfo) public bool IsImmunedToDamage(SpellInfo spellInfo)
{ {
if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) if (spellInfo == null)
return false; return false;
uint shoolMask = (uint)spellInfo.GetSchoolMask(); if (spellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
if (spellInfo.Id != 42292 && spellInfo.Id != 59752) return false;
{
// If m_immuneToSchool type contain this school type, IMMUNE damage. uint schoolMask = (uint)spellInfo.GetSchoolMask();
var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School); // If m_immuneToSchool type contain this school type, IMMUNE damage.
foreach (var immune in schoolList) var schoolList = m_spellImmune[(int)SpellImmunity.School];
if (Convert.ToBoolean(immune.spellType & shoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(immune.spellId))) foreach (var pair in schoolList)
return true; if (Convert.ToBoolean(pair.Key & schoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(pair.Value)))
} return true;
// If m_immuneToDamage type contain magic, IMMUNE damage. // 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) foreach (var immune in damageList)
if (Convert.ToBoolean(immune.spellType & shoolMask)) if (Convert.ToBoolean(immune.Key & schoolMask))
return true; return true;
return false; return false;
@@ -2173,7 +2180,7 @@ namespace Game.Entities
bool isSpellBlocked(Unit victim, SpellInfo spellProto, WeaponAttackType attackType = WeaponAttackType.BaseAttack) bool isSpellBlocked(Unit victim, SpellInfo spellProto, WeaponAttackType attackType = WeaponAttackType.BaseAttack)
{ {
// These spells can't be blocked // 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; return false;
// Can't block when casting/controlled // Can't block when casting/controlled
@@ -2657,28 +2664,6 @@ namespace Game.Entities
return null; 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) public DiminishingLevels GetDiminishing(DiminishingGroup group)
{ {
DiminishingReturn diminish = m_Diminishing[(int)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_modAttackSpeedPct = new float[] { 1.0f, 1.0f, 1.0f };
m_deathState = DeathState.Alive; 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) for (byte i = 0; i < (int)UnitMods.End; ++i)
m_auraModifiersGroup[i] = new float[] { 0.0f, 100.0f, 1.0f, 0.0f, 1.0f }; 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.SchoolImmunity, true);
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.ModUnattackable, true); _me.ApplySpellImmune(0, SpellImmunity.State, AuraType.ModUnattackable, true);
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.SchoolAbsorb, true); _me.ApplySpellImmune(0, SpellImmunity.State, AuraType.SchoolAbsorb, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, Mechanics.Shield, true); _me.ApplySpellImmune(0, SpellImmunity.Mechanic, (uint)Mechanics.Shield, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, Mechanics.Immune_Shield, true); _me.ApplySpellImmune(0, SpellImmunity.Mechanic, (uint)Mechanics.Immune_Shield, true);
// ... Resistance, Split damage, Change stats ... // ... Resistance, Split damage, Change stats ...
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.DamageShield, true); _me.ApplySpellImmune(0, SpellImmunity.State, AuraType.DamageShield, true);
+3
View File
@@ -377,6 +377,9 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Loading SpellInfo diminishing infos..."); Log.outInfo(LogFilter.ServerLoading, "Loading SpellInfo diminishing infos...");
Global.SpellMgr.LoadSpellInfoDiminishing(); Global.SpellMgr.LoadSpellInfoDiminishing();
Log.outInfo(LogFilter.ServerLoading, "Loading SpellInfo immunity infos...");
Global.SpellMgr.LoadSpellInfoImmunities();
Log.outInfo(LogFilter.ServerLoading, "Loading PetFamilySpellsStore Data..."); Log.outInfo(LogFilter.ServerLoading, "Loading PetFamilySpellsStore Data...");
Global.SpellMgr.LoadPetFamilySpellsStore(); Global.SpellMgr.LoadPetFamilySpellsStore();
+12 -295
View File
@@ -2703,7 +2703,7 @@ namespace Game.Spells
{ {
//Players on flying mounts must be immune to polymorph //Players on flying mounts must be immune to polymorph
if (target.IsTypeId(TypeId.Player)) if (target.IsTypeId(TypeId.Player))
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply); target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, (uint)Mechanics.Polymorph, apply);
// Dragonmaw Illusion (overwrite mount model, mounted aura already applied) // Dragonmaw Illusion (overwrite mount model, mounted aura already applied)
if (apply && target.HasAuraEffect(42016, 0) && target.GetMountID() != 0) if (apply && target.HasAuraEffect(42016, 0) && target.GetMountID() != 0)
@@ -2767,228 +2767,13 @@ namespace Game.Spells
/*** IMMUNITY ***/ /*** IMMUNITY ***/
/*********************************************************/ /*********************************************************/
[AuraEffectHandler(AuraType.MechanicImmunityMask)] [AuraEffectHandler(AuraType.MechanicImmunityMask)]
void HandleModStateImmunityMask(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply) void HandleModMechanicImmunityMask(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
{ {
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real)) if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
List<AuraType> aura_immunity_list = new List<AuraType>(); m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
uint mechanic_immunity_list = (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Root)
| (1 << (int)Mechanics.Fear) | (1 << (int)Mechanics.Stun)
| (1 << (int)Mechanics.Sleep) | (1 << (int)Mechanics.Charm)
| (1 << (int)Mechanics.Sapped) | (1 << (int)Mechanics.Horror)
| (1 << (int)Mechanics.Polymorph) | (1 << (int)Mechanics.Disoriented)
| (1 << (int)Mechanics.Freeze) | (1 << (int)Mechanics.Turn);
int miscVal = GetMiscValue();
switch (miscVal)
{
case 27:
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Silence, apply);
aura_immunity_list.Add(AuraType.ModSilence);
break;
case 96:
case 1615:
{
if (HasAmount())
{
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply);
aura_immunity_list.Add(AuraType.ModStun);
aura_immunity_list.Add(AuraType.ModDecreaseSpeed);
aura_immunity_list.Add(AuraType.ModRoot);
aura_immunity_list.Add(AuraType.ModConfuse);
aura_immunity_list.Add(AuraType.ModFear);
aura_immunity_list.Add(AuraType.ModRoot2);
}
break;
}
case 679:
{
if (GetId() == 57742)
{
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply);
aura_immunity_list.Add(AuraType.ModStun);
aura_immunity_list.Add(AuraType.ModDecreaseSpeed);
aura_immunity_list.Add(AuraType.ModRoot);
aura_immunity_list.Add(AuraType.ModConfuse);
aura_immunity_list.Add(AuraType.ModFear);
aura_immunity_list.Add(AuraType.ModRoot2);
}
break;
}
case 1557:
{
if (GetId() == 64187)
{
mechanic_immunity_list = (1 << (int)Mechanics.Stun);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
aura_immunity_list.Add(AuraType.ModStun);
}
else
{
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply);
aura_immunity_list.Add(AuraType.ModStun);
aura_immunity_list.Add(AuraType.ModDecreaseSpeed);
aura_immunity_list.Add(AuraType.ModRoot);
aura_immunity_list.Add(AuraType.ModConfuse);
aura_immunity_list.Add(AuraType.ModFear);
aura_immunity_list.Add(AuraType.ModRoot2);
}
break;
}
case 1614:
case 1694:
{
target.ApplySpellImmune(GetId(), SpellImmunity.Effect, SpellEffectName.AttackMe, apply);
aura_immunity_list.Add(AuraType.ModTaunt);
break;
}
case 1630:
{
if (!HasAmount())
{
target.ApplySpellImmune(GetId(), SpellImmunity.Effect, SpellEffectName.AttackMe, apply);
aura_immunity_list.Add(AuraType.ModTaunt);
}
else
{
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply);
aura_immunity_list.Add(AuraType.ModStun);
aura_immunity_list.Add(AuraType.ModDecreaseSpeed);
aura_immunity_list.Add(AuraType.ModRoot);
aura_immunity_list.Add(AuraType.ModConfuse);
aura_immunity_list.Add(AuraType.ModFear);
aura_immunity_list.Add(AuraType.ModRoot2);
}
break;
}
case 477:
case 1733:
{
if (!HasAmount())
{
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Effect, SpellEffectName.KnockBack, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Effect, SpellEffectName.KnockBackDest, apply);
aura_immunity_list.Add(AuraType.ModStun);
aura_immunity_list.Add(AuraType.ModDecreaseSpeed);
aura_immunity_list.Add(AuraType.ModRoot);
aura_immunity_list.Add(AuraType.ModConfuse);
aura_immunity_list.Add(AuraType.ModFear);
aura_immunity_list.Add(AuraType.ModRoot2);
}
break;
}
case 878:
{
if (GetAmount() == 1)
{
mechanic_immunity_list = (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Stun)
| (1 << (int)Mechanics.Disoriented) | (1 << (int)Mechanics.Freeze);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply);
aura_immunity_list.Add(AuraType.ModStun);
aura_immunity_list.Add(AuraType.ModDecreaseSpeed);
}
break;
}
default:
break;
}
if (aura_immunity_list.Empty())
{
if (Convert.ToBoolean(miscVal & (1 << 10)))
aura_immunity_list.Add(AuraType.ModStun);
if (Convert.ToBoolean(miscVal & (1 << 1)))
aura_immunity_list.Add(AuraType.Transform);
// These flag can be recognized wrong:
if (Convert.ToBoolean(miscVal & (1 << 6)))
aura_immunity_list.Add(AuraType.ModDecreaseSpeed);
if (Convert.ToBoolean(miscVal & (1 << 0)))
{
aura_immunity_list.Add(AuraType.ModRoot);
aura_immunity_list.Add(AuraType.ModRoot2);
}
if (Convert.ToBoolean(miscVal & (1 << 2)))
aura_immunity_list.Add(AuraType.ModConfuse);
if (Convert.ToBoolean(miscVal & (1 << 9)))
aura_immunity_list.Add(AuraType.ModFear);
if (Convert.ToBoolean(miscVal & (1 << 7)))
aura_immunity_list.Add(AuraType.ModDisarm);
}
// apply immunities
foreach (var iter in aura_immunity_list)
target.ApplySpellImmune(GetId(), SpellImmunity.State, iter, apply);
if (apply && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity))
{
target.RemoveAurasWithMechanic(mechanic_immunity_list, AuraRemoveMode.Default, GetId());
foreach (var iter in aura_immunity_list)
target.RemoveAurasByType(iter);
}
} }
[AuraEffectHandler(AuraType.MechanicImmunity)] [AuraEffectHandler(AuraType.MechanicImmunity)]
@@ -2998,52 +2783,7 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
uint mechanic; m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
switch (GetId())
{
case 34471: // The Beast Within
case 19574: // Bestial Wrath
mechanic = (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Knockout, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Banish, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Shackle, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Daze, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply);
break;
case 42292: // PvP trinket
case 59752: // Every Man for Himself
case 53490: // Bullheaded
mechanic = (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
// Actually we should apply immunities here, too, but the aura has only 100 ms duration, so there is practically no point
break;
case 54508: // Demonic Empowerment
mechanic = (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Root);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply);
break;
default:
if (GetMiscValue() < 1)
return;
mechanic = (uint)(1 << GetMiscValue());
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, GetMiscValue(), apply);
break;
}
if (apply && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity))
target.RemoveAurasWithMechanic(mechanic, AuraRemoveMode.Default, GetId());
} }
[AuraEffectHandler(AuraType.EffectImmunity)] [AuraEffectHandler(AuraType.EffectImmunity)]
@@ -3053,8 +2793,7 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Effect, GetMiscValue(), apply);
// when removing flag aura, handle flag drop // when removing flag aura, handle flag drop
Player player = target.ToPlayer(); Player player = target.ToPlayer();
@@ -3078,11 +2817,7 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
target.ApplySpellImmune(GetId(), SpellImmunity.State, GetMiscValue(), apply);
if (apply && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity))
target.RemoveAurasByType((AuraType)GetMiscValue(), ObjectGuid.Empty, GetBase());
} }
[AuraEffectHandler(AuraType.SchoolImmunity)] [AuraEffectHandler(AuraType.SchoolImmunity)]
@@ -3092,8 +2827,7 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
target.ApplySpellImmune(GetId(), SpellImmunity.School, (uint)GetMiscValue(), (apply));
if (GetSpellInfo().Mechanic == Mechanics.Banish) if (GetSpellInfo().Mechanic == Mechanics.Banish)
{ {
@@ -3103,9 +2837,9 @@ namespace Game.Spells
{ {
bool banishFound = false; bool banishFound = false;
var banishAuras = target.GetAuraEffectsByType(GetAuraType()); var banishAuras = target.GetAuraEffectsByType(GetAuraType());
foreach (var eff in banishAuras) foreach (var aurEff in banishAuras)
{ {
if (eff.GetSpellInfo().Mechanic == Mechanics.Banish) if (aurEff.GetSpellInfo().Mechanic == Mechanics.Banish)
{ {
banishFound = true; banishFound = true;
break; break;
@@ -3124,21 +2858,6 @@ namespace Game.Spells
if (GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity) if (GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity)
&& GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield)) && GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield))
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection);
/// @todo optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else
if ((apply) && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity) && GetSpellInfo().IsPositive()) //Only positive immunity removes auras
{
int schoolMask = GetMiscValue();
target.RemoveAppliedAuras(aurApp1 =>
{
SpellInfo spell = aurApp1.GetBase().GetSpellInfo();
return Convert.ToBoolean((int)spell.GetSchoolMask() & schoolMask)//Check for school mask
&& GetSpellInfo().CanDispelAura(spell)
&& !aurApp1.IsPositive() //Don't remove positive spells
&& !spell.IsPassive() // Don't remove passive auras
&& spell.Id != GetId(); //Don't remove self
});
}
} }
[AuraEffectHandler(AuraType.DamageImmunity)] [AuraEffectHandler(AuraType.DamageImmunity)]
@@ -3148,8 +2867,7 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Damage, (uint)GetMiscValue(), apply);
} }
[AuraEffectHandler(AuraType.DispelImmunity)] [AuraEffectHandler(AuraType.DispelImmunity)]
@@ -3159,8 +2877,7 @@ namespace Game.Spells
return; return;
Unit target = aurApp.GetTarget(); Unit target = aurApp.GetTarget();
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
target.ApplySpellDispelImmunity(m_spellInfo, (DispelType)GetMiscValue(), (apply));
} }
/*********************************************************/ /*********************************************************/
@@ -4608,7 +4325,7 @@ namespace Game.Spells
{ {
// Recently Bandaged // Recently Bandaged
case 11196: case 11196:
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, GetMiscValue(), apply); target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, (uint)GetMiscValue(), apply);
break; break;
// Unstable Power // Unstable Power
case 24658: case 24658:
+284 -221
View File
@@ -2091,7 +2091,7 @@ namespace Game.Spells
return SpellMissInfo.Evade; return SpellMissInfo.Evade;
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case // For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
if (m_spellInfo.Speed != 0.0f && (unit.IsImmunedToDamage(m_spellInfo) || unit.IsImmunedToSpell(m_spellInfo))) if (m_spellInfo.Speed != 0.0f && unit.IsImmunedToSpell(m_spellInfo))
return SpellMissInfo.Immune; return SpellMissInfo.Immune;
// disable effects to which unit is immune // disable effects to which unit is immune
@@ -2523,7 +2523,8 @@ namespace Game.Spells
if (Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreComboPoints) || m_CastItem != null || m_caster.m_playerMovingMe == null) if (Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreComboPoints) || m_CastItem != null || m_caster.m_playerMovingMe == null)
m_needComboPoints = false; m_needComboPoints = false;
SpellCastResult result = CheckCast(true); uint param1 = 0, param2 = 0;
SpellCastResult result = CheckCast(true, ref param1, ref param2);
// target is checked in too many locations and with different results to handle each of them // target is checked in too many locations and with different results to handle each of them
// handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks
if (Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreTargetCheck) && result == SpellCastResult.BadTargets) if (Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreTargetCheck) && result == SpellCastResult.BadTargets)
@@ -2548,7 +2549,10 @@ namespace Game.Spells
m_caster.ToPlayer().SetSpellModTakingSpell(this, false); m_caster.ToPlayer().SetSpellModTakingSpell(this, false);
} }
SendCastResult(result); if (param1 != 0 || param2 != 0)
SendCastResult(result, param1, param2);
else
SendCastResult(result);
finish(false); finish(false);
return; return;
@@ -2749,10 +2753,11 @@ namespace Game.Spells
// skip check if done already (for instant cast spells for example) // skip check if done already (for instant cast spells for example)
if (!skipCheck) if (!skipCheck)
{ {
SpellCastResult castResult = CheckCast(false); uint param1 = 0, param2 = 0;
SpellCastResult castResult = CheckCast(false, ref param1, ref param2);
if (castResult != SpellCastResult.SpellCastOk) if (castResult != SpellCastResult.SpellCastOk)
{ {
SendCastResult(castResult); SendCastResult(castResult, param1, param2);
SendInterrupted(0); SendInterrupted(0);
//restore spell mods //restore spell mods
if (m_caster.IsTypeId(TypeId.Player)) if (m_caster.IsTypeId(TypeId.Player))
@@ -3316,7 +3321,7 @@ namespace Game.Spells
m_caster.AttackStop(); m_caster.AttackStop();
} }
static void FillSpellCastFailedArgs<T>(T packet, ObjectGuid castId, SpellInfo spellInfo, SpellCastResult result, SpellCustomErrors customError, uint[] misc, Player caster) where T : CastFailedBase static void FillSpellCastFailedArgs<T>(T packet, ObjectGuid castId, SpellInfo spellInfo, SpellCastResult result, SpellCustomErrors customError, uint? param1, uint? param2, Player caster) where T : CastFailedBase
{ {
packet.CastID = castId; packet.CastID = castId;
packet.SpellID = (int)spellInfo.Id; packet.SpellID = (int)spellInfo.Id;
@@ -3325,112 +3330,183 @@ namespace Game.Spells
switch (result) switch (result)
{ {
case SpellCastResult.NotReady: case SpellCastResult.NotReady:
packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag) if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = 0;// unknown (value 1 update cooldowns on client flag)
break; break;
case SpellCastResult.RequiresSpellFocus: case SpellCastResult.RequiresSpellFocus:
packet.FailedArg1 = (int)spellInfo.RequiresSpellFocus; // SpellFocusObject.dbc id if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = (int)spellInfo.RequiresSpellFocus; // SpellFocusObject.dbc id
break; break;
case SpellCastResult.RequiresArea: // AreaTable.dbc id case SpellCastResult.RequiresArea: // AreaTable.dbc id
// hardcode areas limitation case if (param1.HasValue)
switch (spellInfo.Id) packet.FailedArg1 = (int)param1;
else
{ {
case 41617: // Cenarion Mana Salve // hardcode areas limitation case
case 41619: // Cenarion Healing Salve switch (spellInfo.Id)
packet.FailedArg1 = 3905; {
break; case 41617: // Cenarion Mana Salve
case 41618: // Bottled Nethergon Energy case 41619: // Cenarion Healing Salve
case 41620: // Bottled Nethergon Vapor packet.FailedArg1 = 3905;
packet.FailedArg1 = 3842; break;
break; case 41618: // Bottled Nethergon Energy
case 45373: // Bloodberry Elixir case 41620: // Bottled Nethergon Vapor
packet.FailedArg1 = 4075; packet.FailedArg1 = 3842;
break; break;
default: // default case (don't must be) case 45373: // Bloodberry Elixir
packet.FailedArg1 = 0; packet.FailedArg1 = 4075;
break; break;
default: // default case (don't must be)
packet.FailedArg1 = 0;
break;
}
} }
break; break;
case SpellCastResult.Totems: case SpellCastResult.Totems:
if (spellInfo.Totem[0] != 0) if (param1.HasValue)
packet.FailedArg1 = (int)spellInfo.Totem[0]; {
if (spellInfo.Totem[1] != 0) packet.FailedArg1 = (int)param1;
packet.FailedArg2 = (int)spellInfo.Totem[1]; if (param2.HasValue)
packet.FailedArg2 = (int)param2;
}
else
{
if (spellInfo.Totem[0] != 0)
packet.FailedArg1 = (int)spellInfo.Totem[0];
if (spellInfo.Totem[1] != 0)
packet.FailedArg2 = (int)spellInfo.Totem[1];
}
break; break;
case SpellCastResult.TotemCategory: case SpellCastResult.TotemCategory:
if (spellInfo.TotemCategory[0] != 0) if (param1.HasValue)
packet.FailedArg1 = (int)spellInfo.TotemCategory[0]; {
if (spellInfo.TotemCategory[1] != 0) packet.FailedArg1 = (int)param1;
packet.FailedArg2 = (int)spellInfo.TotemCategory[1]; if (param2.HasValue)
packet.FailedArg2 = (int)param2;
}
else
{
if (spellInfo.TotemCategory[0] != 0)
packet.FailedArg1 = (int)spellInfo.TotemCategory[0];
if (spellInfo.TotemCategory[1] != 0)
packet.FailedArg2 = (int)spellInfo.TotemCategory[1];
}
break; break;
case SpellCastResult.EquippedItemClass: case SpellCastResult.EquippedItemClass:
case SpellCastResult.EquippedItemClassMainhand: case SpellCastResult.EquippedItemClassMainhand:
case SpellCastResult.EquippedItemClassOffhand: case SpellCastResult.EquippedItemClassOffhand:
packet.FailedArg1 = (int)spellInfo.EquippedItemClass; if (param1.HasValue && param2.HasValue)
packet.FailedArg2 = spellInfo.EquippedItemSubClassMask; {
packet.FailedArg1 = (int)param1;
packet.FailedArg2 = (int)param2;
}
else
{
packet.FailedArg1 = (int)spellInfo.EquippedItemClass;
packet.FailedArg2 = spellInfo.EquippedItemSubClassMask;
}
break; break;
case SpellCastResult.TooManyOfItem: case SpellCastResult.TooManyOfItem:
{ {
uint item = 0; if (param1.HasValue)
foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(caster.GetMap().GetDifficultyID())) packet.FailedArg1 = (int)param1;
if (effect.ItemType != 0) else
item = effect.ItemType; {
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item); uint item = 0;
if (proto != null && proto.GetItemLimitCategory() != 0) foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(caster.GetMap().GetDifficultyID()))
packet.FailedArg1 = (int)proto.GetItemLimitCategory(); if (effect.ItemType != 0)
item = effect.ItemType;
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item);
if (proto != null && proto.GetItemLimitCategory() != 0)
packet.FailedArg1 = (int)proto.GetItemLimitCategory();
}
break; break;
} }
case SpellCastResult.PreventedByMechanic: case SpellCastResult.PreventedByMechanic:
packet.FailedArg1 = (int)spellInfo.GetAllEffectsMechanicMask(); // SpellMechanic.dbc id if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = (int)spellInfo.GetAllEffectsMechanicMask(); // SpellMechanic.dbc id
break; break;
case SpellCastResult.NeedExoticAmmo: case SpellCastResult.NeedExoticAmmo:
packet.FailedArg1 = spellInfo.EquippedItemSubClassMask; // seems correct... if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = spellInfo.EquippedItemSubClassMask; // seems correct...
break; break;
case SpellCastResult.NeedMoreItems: case SpellCastResult.NeedMoreItems:
packet.FailedArg1 = 0; // Item id if (param1.HasValue && param2.HasValue)
packet.FailedArg2 = 0; // Item count? {
packet.FailedArg1 = (int)param1;
packet.FailedArg2 = (int)param2;
}
else
{
packet.FailedArg1 = 0; // Item id
packet.FailedArg2 = 0; // Item count?
}
break; break;
case SpellCastResult.MinSkill: case SpellCastResult.MinSkill:
packet.FailedArg1 = 0; // SkillLine.dbc id if (param1.HasValue && param2.HasValue)
packet.FailedArg2 = 0; // required skill value {
packet.FailedArg1 = (int)param1;
packet.FailedArg2 = (int)param2;
}
else
{
packet.FailedArg1 = 0; // SkillLine.dbc id
packet.FailedArg2 = 0; // required skill value
}
break; break;
case SpellCastResult.FishingTooLow: case SpellCastResult.FishingTooLow:
packet.FailedArg1 = 0; // required fishing skill if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = 0; // required fishing skill
break; break;
case SpellCastResult.CustomError: case SpellCastResult.CustomError:
packet.FailedArg1 = (int)customError; packet.FailedArg1 = (int)customError;
break; break;
case SpellCastResult.Silenced: case SpellCastResult.Silenced:
packet.FailedArg1 = 0; // Unknown if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = 0; // Unknown
break; break;
case SpellCastResult.Reagents: case SpellCastResult.Reagents:
{ {
uint missingItem = 0; if (param1.HasValue)
for (uint i = 0; i < SpellConst.MaxReagents; i++) packet.FailedArg1 = (int)param1;
else
{ {
if (spellInfo.Reagent[i] <= 0) uint missingItem = 0;
continue; for (uint i = 0; i < SpellConst.MaxReagents; i++)
uint itemid = (uint)spellInfo.Reagent[i];
uint itemcount = spellInfo.ReagentCount[i];
if (!caster.HasItemCount(itemid, itemcount))
{ {
missingItem = itemid; if (spellInfo.Reagent[i] <= 0)
break; continue;
}
}
packet.FailedArg1 = (int)missingItem; // first missing item uint itemid = (uint)spellInfo.Reagent[i];
uint itemcount = spellInfo.ReagentCount[i];
if (!caster.HasItemCount(itemid, itemcount))
{
missingItem = itemid;
break;
}
}
packet.FailedArg1 = (int)missingItem; // first missing item
}
break; break;
} }
case SpellCastResult.CantUntalent: case SpellCastResult.CantUntalent:
{ {
if (misc != null) Contract.Assert(param1.HasValue);
{ packet.FailedArg1 = (int)param1;
TalentRecord talent = CliDB.TalentStorage.LookupByKey(misc[0]);
if (talent != null)
packet.FailedArg1 = (int)talent.SpellID;
}
break; break;
} }
// TODO: SPELL_FAILED_NOT_STANDING // TODO: SPELL_FAILED_NOT_STANDING
@@ -3439,7 +3515,7 @@ namespace Game.Spells
} }
} }
public void SendCastResult(SpellCastResult result) public void SendCastResult(SpellCastResult result, uint? param1 = null, uint? param2 = null)
{ {
if (result == SpellCastResult.SpellCastOk) if (result == SpellCastResult.SpellCastOk)
return; return;
@@ -3447,7 +3523,7 @@ namespace Game.Spells
if (!m_caster.IsTypeId(TypeId.Player)) if (!m_caster.IsTypeId(TypeId.Player))
return; return;
if (m_caster.ToPlayer().GetSession().PlayerLoading()) // don't send cast results at loading time if (m_caster.ToPlayer().IsLoading()) // don't send cast results at loading time
return; return;
if (_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.DontReportCastError)) if (_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.DontReportCastError))
@@ -3455,11 +3531,11 @@ namespace Game.Spells
CastFailed castFailed = new CastFailed(); CastFailed castFailed = new CastFailed();
castFailed.SpellXSpellVisualID = (int)m_SpellVisual; castFailed.SpellXSpellVisualID = (int)m_SpellVisual;
FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, m_misc.GetRawData(), m_caster.ToPlayer()); FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, param1, param2, m_caster.ToPlayer());
m_caster.ToPlayer().SendPacket(castFailed); m_caster.ToPlayer().SendPacket(castFailed);
} }
public void SendPetCastResult(SpellCastResult result) public void SendPetCastResult(SpellCastResult result, uint? param1 = null, uint? param2 = null)
{ {
if (result == SpellCastResult.SpellCastOk) if (result == SpellCastResult.SpellCastOk)
return; return;
@@ -3472,18 +3548,18 @@ namespace Game.Spells
result = SpellCastResult.DontReport; result = SpellCastResult.DontReport;
PetCastFailed petCastFailed = new PetCastFailed(); PetCastFailed petCastFailed = new PetCastFailed();
FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SpellCustomErrors.None, m_misc.GetRawData(), owner.ToPlayer()); FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SpellCustomErrors.None, param1, param2, owner.ToPlayer());
owner.ToPlayer().SendPacket(petCastFailed); owner.ToPlayer().SendPacket(petCastFailed);
} }
public static void SendCastResult(Player caster, SpellInfo spellInfo, uint spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError = SpellCustomErrors.None, uint[] misc = null) public static void SendCastResult(Player caster, SpellInfo spellInfo, uint spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError = SpellCustomErrors.None, uint? param1 = null, uint? param2 = null)
{ {
if (result == SpellCastResult.SpellCastOk) if (result == SpellCastResult.SpellCastOk)
return; return;
CastFailed packet = new CastFailed(); CastFailed packet = new CastFailed();
packet.SpellXSpellVisualID = (int)spellVisual; packet.SpellXSpellVisualID = (int)spellVisual;
FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, misc, caster); FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, param1, param2, caster);
caster.SendPacket(packet); caster.SendPacket(packet);
} }
@@ -4329,6 +4405,12 @@ namespace Game.Spells
} }
public SpellCastResult CheckCast(bool strict) public SpellCastResult CheckCast(bool strict)
{
uint param1 = 0, param2 = 0;
return CheckCast(strict, ref param1, ref param2);
}
public SpellCastResult CheckCast(bool strict, ref uint param1, ref uint param2)
{ {
SpellCastResult castResult = SpellCastResult.SpellCastOk; SpellCastResult castResult = SpellCastResult.SpellCastOk;
// check death state // check death state
@@ -4395,13 +4477,15 @@ namespace Game.Spells
bool checkForm = true; bool checkForm = true;
// Ignore form req aura // Ignore form req aura
var ignore = m_caster.GetAuraEffectsByType(AuraType.ModIgnoreShapeshift); var ignore = m_caster.GetAuraEffectsByType(AuraType.ModIgnoreShapeshift);
foreach (var aura in ignore) foreach (var aurEff in ignore)
{ {
if (!aura.IsAffectingSpell(m_spellInfo)) if (!aurEff.IsAffectingSpell(m_spellInfo))
continue; continue;
checkForm = false; checkForm = false;
break; break;
} }
if (checkForm) if (checkForm)
{ {
// Cannot be used in this stance/form // Cannot be used in this stance/form
@@ -4630,7 +4714,7 @@ namespace Game.Spells
// always (except passive spells) check items (focus object can be required for any type casts) // always (except passive spells) check items (focus object can be required for any type casts)
if (!m_spellInfo.IsPassive()) if (!m_spellInfo.IsPassive())
{ {
castResult = CheckItems(); castResult = CheckItems(ref param1, ref param2);
if (castResult != SpellCastResult.SpellCastOk) if (castResult != SpellCastResult.SpellCastOk)
return castResult; return castResult;
} }
@@ -4650,7 +4734,7 @@ namespace Game.Spells
if (!Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreCasterAuras)) if (!Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreCasterAuras))
{ {
castResult = CheckCasterAuras(); castResult = CheckCasterAuras(ref param1);
if (castResult != SpellCastResult.SpellCastOk) if (castResult != SpellCastResult.SpellCastOk)
return castResult; return castResult;
} }
@@ -4909,7 +4993,7 @@ namespace Game.Spells
break; break;
if (!m_caster.IsTypeId(TypeId.Player) // only players can open locks, gather etc. if (!m_caster.IsTypeId(TypeId.Player) // only players can open locks, gather etc.
// we need a go target in case of TARGET_GAMEOBJECT_TARGET // we need a go target in case of TARGET_GAMEOBJECT_TARGET
|| (effect.TargetA.GetTarget() == Targets.GameobjectTarget && m_targets.GetGOTarget() == null)) || (effect.TargetA.GetTarget() == Targets.GameobjectTarget && m_targets.GetGOTarget() == null))
return SpellCastResult.BadTargets; return SpellCastResult.BadTargets;
@@ -5139,7 +5223,10 @@ namespace Game.Spells
if (talent == null) if (talent == null)
return SpellCastResult.DontReport; return SpellCastResult.DontReport;
if (m_caster.GetSpellHistory().HasCooldown(talent.SpellID)) if (m_caster.GetSpellHistory().HasCooldown(talent.SpellID))
{
param1 = talent.SpellID;
return SpellCastResult.CantUntalent; return SpellCastResult.CantUntalent;
}
break; break;
} }
case SpellEffectName.GiveArtifactPower: case SpellEffectName.GiveArtifactPower:
@@ -5362,146 +5449,109 @@ namespace Game.Spells
return CheckCast(true); return CheckCast(true);
} }
SpellCastResult CheckCasterAuras() SpellCastResult CheckCasterAuras(ref uint param1)
{ {
// spells totally immuned to caster auras (wsg flag drop, give marks etc) // spells totally immuned to caster auras (wsg flag drop, give marks etc)
if (m_spellInfo.HasAttribute(SpellAttr6.IgnoreCasterAuras)) if (m_spellInfo.HasAttribute(SpellAttr6.IgnoreCasterAuras))
return SpellCastResult.SpellCastOk; return SpellCastResult.SpellCastOk;
int school_immune = 0; bool usableWhileStunned = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileStunned);
uint mechanic_immune = 0; bool usableWhileFeared = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileFeared);
uint dispel_immune = 0; bool usableWhileConfused = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileConfused);
if (m_spellInfo.HasAttribute(SpellAttr7.UsableInStunFearConfusion))
// Check if the spell grants school or mechanic immunity.
// We use bitmasks so the loop is done only once and not on every aura check below.
if (m_spellInfo.HasAttribute(SpellAttr1.DispelAurasOnImmunity))
{ {
foreach (SpellEffectInfo effect in GetEffects()) usableWhileStunned = true;
{ usableWhileFeared = true;
if (effect == null) usableWhileConfused = true;
continue;
if (effect.ApplyAuraName == AuraType.SchoolImmunity)
school_immune |= effect.MiscValue;
else if (effect.ApplyAuraName == AuraType.MechanicImmunity)
mechanic_immune |= (uint)(1 << effect.MiscValue);
else if (effect.ApplyAuraName == AuraType.DispelImmunity)
dispel_immune |= SpellInfo.GetDispelMask((DispelType)effect.MiscValue);
}
// immune movement impairment and loss of control
if (m_spellInfo.Id == 42292 || m_spellInfo.Id == 59752 || m_spellInfo.Id == 19574 || m_spellInfo.Id == 53490)
mechanic_immune = (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
} }
bool usableInStun = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileStunned);
// Check whether the cast should be prevented by any state you might have. // Check whether the cast should be prevented by any state you might have.
SpellCastResult prevented_reason = SpellCastResult.SpellCastOk; SpellCastResult result = SpellCastResult.SpellCastOk;
// Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out // Get unit state
UnitFlags unitflag = (UnitFlags)m_caster.GetUInt32Value(UnitFields.Flags); // Get unit state UnitFlags unitflag = (UnitFlags)m_caster.GetUInt32Value(UnitFields.Flags);
if (Convert.ToBoolean(unitflag & UnitFlags.Stunned)) if (!m_caster.GetCharmerGUID().IsEmpty())
{ {
// spell is usable while stunned, check if caster has allowed stun auras, another stun types must prevent cast spell Unit charmer = m_caster.GetCharmer();
if (usableInStun) if (charmer)
{ if (charmer.GetUnitBeingMoved() != m_caster && CheckCasterNotImmunedCharmAuras(ref param1))
uint allowedStunMask = result = SpellCastResult.Charmed;
1 << (int)Mechanics.Stun
| 1 << (int)Mechanics.Freeze
| 1 << (int)Mechanics.Sapped
| 1 << (int)Mechanics.Sleep;
bool foundNotStun = false;
var stunAuras = m_caster.GetAuraEffectsByType(AuraType.ModStun);
foreach (var auraEffect in stunAuras)
{
uint mechanicMask = auraEffect.GetSpellInfo().GetAllEffectsMechanicMask();
if (mechanicMask != 0 && !Convert.ToBoolean(mechanicMask & allowedStunMask))
{
foundNotStun = true;
break;
}
}
if (foundNotStun)
prevented_reason = SpellCastResult.Stunned;
}
else
prevented_reason = SpellCastResult.Stunned;
} }
else if (unitflag.HasAnyFlag(UnitFlags.Confused) && !m_spellInfo.HasAttribute(SpellAttr5.UsableWhileConfused)) else if (unitflag.HasAnyFlag(UnitFlags.Stunned) && !usableWhileStunned && CheckCasterNotImmunedStunAuras(ref param1))
prevented_reason = SpellCastResult.Confused; result = SpellCastResult.Stunned;
else if (unitflag.HasAnyFlag(UnitFlags.Fleeing) && !m_spellInfo.HasAttribute(SpellAttr5.UsableWhileFeared)) else if (unitflag.HasAnyFlag(UnitFlags.Silenced) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence) && CheckCasterNotImmunedSilenceAuras(ref param1))
prevented_reason = SpellCastResult.Fleeing; result = SpellCastResult.Silenced;
else if (unitflag.HasAnyFlag(UnitFlags.Silenced) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence)) else if (unitflag.HasAnyFlag(UnitFlags.Pacified) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Pacify) && CheckCasterNotImmunedPacifyAuras(ref param1))
prevented_reason = SpellCastResult.Silenced; result = SpellCastResult.Pacified;
else if (unitflag.HasAnyFlag(UnitFlags.Pacified) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Pacify)) else if (unitflag.HasAnyFlag(UnitFlags.Fleeing) && !usableWhileFeared && CheckCasterNotImmunedFearAuras(ref param1))
prevented_reason = SpellCastResult.Pacified; result = SpellCastResult.Fleeing;
else if (unitflag.HasAnyFlag(UnitFlags.Confused) && !usableWhileConfused && CheckCasterNotImmunedDisorientAuras(ref param1))
result = SpellCastResult.Confused;
else if (m_caster.HasFlag(UnitFields.Flags2, UnitFlags2.NoActions) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.NoActions)) else if (m_caster.HasFlag(UnitFields.Flags2, UnitFlags2.NoActions) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.NoActions))
prevented_reason = SpellCastResult.NoActions; result = SpellCastResult.NoActions;
// Attr must make flag drop spell totally immune from all effects // Attr must make flag drop spell totally immune from all effects
if (prevented_reason != SpellCastResult.SpellCastOk) if (result != SpellCastResult.SpellCastOk)
{ return (param1 != 0) ? SpellCastResult.PreventedByMechanic : result;
if (school_immune != 0 || mechanic_immune != 0 || dispel_immune != 0)
{
//Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
foreach (var pair in m_caster.GetAppliedAuras())
{
Aura aura = pair.Value.GetBase();
SpellInfo auraInfo = aura.GetSpellInfo();
if (Convert.ToBoolean(auraInfo.GetAllEffectsMechanicMask() & mechanic_immune))
continue;
if (Convert.ToBoolean((int)auraInfo.GetSchoolMask() & school_immune) && !auraInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune))
continue;
if (Convert.ToBoolean((int)auraInfo.GetDispelMask() & dispel_immune))
continue;
//Make a second check for spell failed so the right SPELL_FAILED message is returned.
//That is needed when your casting is prevented by multiple states and you are only immune to some of them.
foreach (SpellEffectInfo effect in GetEffects())
{
if (effect == null)
continue;
AuraEffect part = aura.GetEffect(effect.EffectIndex);
if (part != null)
{
switch (part.GetAuraType())
{
case AuraType.ModStun:
if (!usableInStun || !Convert.ToBoolean(auraInfo.GetAllEffectsMechanicMask() & (1 << (int)Mechanics.Stun)))
return SpellCastResult.Stunned;
break;
case AuraType.ModConfuse:
if (!m_spellInfo.HasAttribute(SpellAttr5.UsableWhileConfused))
return SpellCastResult.Confused;
break;
case AuraType.ModFear:
if (!m_spellInfo.HasAttribute(SpellAttr5.UsableWhileFeared))
return SpellCastResult.Fleeing;
break;
case AuraType.ModSilence:
case AuraType.ModPacify:
case AuraType.ModPacifySilence:
if (m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Pacify))
return SpellCastResult.Pacified;
else if (m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence))
return SpellCastResult.Silenced;
break;
default:
break;
}
}
}
}
}
// You are prevented from casting and the spell casted does not grant immunity. Return a failed error.
else
return prevented_reason;
}
return SpellCastResult.SpellCastOk; return SpellCastResult.SpellCastOk;
} }
// based on sub_00804430 from 12340 client
bool CheckCasterHasNotImmunedAuraType(AuraType auraType, ref uint param1)
{
// Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
var auraEffects = m_caster.GetAuraEffectsByType(auraType);
if (auraEffects.Empty())
return false;
foreach (AuraEffect aurEff in auraEffects)
{
if (m_spellInfo.CanSpellCastOverrideAuraEffect(aurEff))
continue;
param1 = (uint)aurEff.GetSpellEffectInfo().Mechanic;
if (param1 == 0)
param1 = (uint)aurEff.GetSpellInfo().Mechanic;
return true;
}
return false;
}
bool CheckCasterNotImmunedCharmAuras(ref uint param1)
{
return CheckCasterHasNotImmunedAuraType(AuraType.ModCharm, ref param1) ||
CheckCasterHasNotImmunedAuraType(AuraType.AoeCharm, ref param1) ||
CheckCasterHasNotImmunedAuraType(AuraType.ModPossess, ref param1);
}
bool CheckCasterNotImmunedStunAuras(ref uint param1)
{
return CheckCasterHasNotImmunedAuraType(AuraType.ModStun, ref param1);
}
bool CheckCasterNotImmunedSilenceAuras(ref uint param1)
{
return CheckCasterHasNotImmunedAuraType(AuraType.ModSilence, ref param1) ||
CheckCasterHasNotImmunedAuraType(AuraType.ModPacifySilence, ref param1);
}
bool CheckCasterNotImmunedPacifyAuras(ref uint param1)
{
return CheckCasterHasNotImmunedAuraType(AuraType.ModPacify, ref param1) ||
CheckCasterHasNotImmunedAuraType(AuraType.ModPacifySilence, ref param1);
}
bool CheckCasterNotImmunedFearAuras(ref uint param1)
{
return CheckCasterHasNotImmunedAuraType(AuraType.ModFear, ref param1);
}
bool CheckCasterNotImmunedDisorientAuras(ref uint param1)
{
return CheckCasterHasNotImmunedAuraType(AuraType.ModConfuse, ref param1);
}
SpellCastResult CheckArenaAndRatedBattlegroundCastRules() SpellCastResult CheckArenaAndRatedBattlegroundCastRules()
{ {
bool isRatedBattleground = false; // NYI bool isRatedBattleground = false; // NYI
@@ -5727,13 +5777,15 @@ namespace Game.Spells
return SpellCastResult.SpellCastOk; return SpellCastResult.SpellCastOk;
} }
SpellCastResult CheckItems() SpellCastResult CheckItems(ref uint param1, ref uint param2)
{ {
Player player = m_caster.ToPlayer(); Player player = m_caster.ToPlayer();
if (!player) if (!player)
return SpellCastResult.SpellCastOk; return SpellCastResult.SpellCastOk;
if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreItemCheck))
return SpellCastResult.SpellCastOk;
if (m_CastItem == null) if (m_CastItem == null)
{ {
if (!m_castItemGUID.IsEmpty()) if (!m_castItemGUID.IsEmpty())
@@ -5809,13 +5861,11 @@ namespace Game.Spells
// check target item // check target item
if (!m_targets.GetItemTargetGUID().IsEmpty()) if (!m_targets.GetItemTargetGUID().IsEmpty())
{ {
if (!m_caster.IsTypeId(TypeId.Player)) Item item = m_targets.GetItemTarget();
return SpellCastResult.BadTargets; if (item == null)
if (m_targets.GetItemTarget() == null)
return SpellCastResult.ItemGone; return SpellCastResult.ItemGone;
if (!m_targets.GetItemTarget().IsFitToSpellRequirements(m_spellInfo)) if (!item.IsFitToSpellRequirements(m_spellInfo))
return SpellCastResult.EquippedItemClass; return SpellCastResult.EquippedItemClass;
} }
// if not item target then required item must be equipped // if not item target then required item must be equipped
@@ -5868,7 +5918,10 @@ namespace Game.Spells
} }
} }
if (!player.HasItemCount(itemid, itemcount)) if (!player.HasItemCount(itemid, itemcount))
{
param1 = itemid;
return SpellCastResult.Reagents; return SpellCastResult.Reagents;
}
} }
} }
@@ -6073,21 +6126,26 @@ namespace Game.Spells
} }
case SpellEffectName.Prospecting: case SpellEffectName.Prospecting:
{ {
if (m_targets.GetItemTarget() == null) Item item = m_targets.GetItemTarget();
if (!item)
return SpellCastResult.CantBeProspected; return SpellCastResult.CantBeProspected;
//ensure item is a prospectable ore //ensure item is a prospectable ore
if (!Convert.ToBoolean(m_targets.GetItemTarget().GetTemplate().GetFlags() & ItemFlags.IsProspectable)) if (!Convert.ToBoolean(item.GetTemplate().GetFlags() & ItemFlags.IsProspectable))
return SpellCastResult.CantBeProspected; return SpellCastResult.CantBeProspected;
//prevent prospecting in trade slot //prevent prospecting in trade slot
if (m_targets.GetItemTarget().GetOwnerGUID() != m_caster.GetGUID()) if (item.GetOwnerGUID() != m_caster.GetGUID())
return SpellCastResult.CantBeProspected; return SpellCastResult.CantBeProspected;
//Check for enough skill in jewelcrafting //Check for enough skill in jewelcrafting
uint item_prospectingskilllevel = m_targets.GetItemTarget().GetTemplate().GetRequiredSkillRank(); uint item_prospectingskilllevel = item.GetTemplate().GetRequiredSkillRank();
if (item_prospectingskilllevel > player.GetSkillValue(SkillType.Jewelcrafting)) if (item_prospectingskilllevel > player.GetSkillValue(SkillType.Jewelcrafting))
return SpellCastResult.LowCastlevel; return SpellCastResult.LowCastlevel;
//make sure the player has the required ores in inventory //make sure the player has the required ores in inventory
if (m_targets.GetItemTarget().GetCount() < 5) if (item.GetCount() < 5)
{
param1 = item.GetEntry();
param2 = 5;
return SpellCastResult.NeedMoreItems; return SpellCastResult.NeedMoreItems;
}
if (!LootStorage.Prospecting.HaveLootFor(m_targets.GetItemTargetEntry())) if (!LootStorage.Prospecting.HaveLootFor(m_targets.GetItemTargetEntry()))
return SpellCastResult.CantBeProspected; return SpellCastResult.CantBeProspected;
@@ -6096,21 +6154,26 @@ namespace Game.Spells
} }
case SpellEffectName.Milling: case SpellEffectName.Milling:
{ {
if (m_targets.GetItemTarget() == null) Item item = m_targets.GetItemTarget();
if (!item)
return SpellCastResult.CantBeMilled; return SpellCastResult.CantBeMilled;
//ensure item is a millable herb //ensure item is a millable herb
if (!(m_targets.GetItemTarget().GetTemplate().GetFlags().HasAnyFlag(ItemFlags.IsMillable))) if (!(item.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.IsMillable)))
return SpellCastResult.CantBeMilled; return SpellCastResult.CantBeMilled;
//prevent milling in trade slot //prevent milling in trade slot
if (m_targets.GetItemTarget().GetOwnerGUID() != m_caster.GetGUID()) if (item.GetOwnerGUID() != m_caster.GetGUID())
return SpellCastResult.CantBeMilled; return SpellCastResult.CantBeMilled;
//Check for enough skill in inscription //Check for enough skill in inscription
uint item_millingskilllevel = m_targets.GetItemTarget().GetTemplate().GetRequiredSkillRank(); uint item_millingskilllevel = item.GetTemplate().GetRequiredSkillRank();
if (item_millingskilllevel > player.GetSkillValue(SkillType.Inscription)) if (item_millingskilllevel > player.GetSkillValue(SkillType.Inscription))
return SpellCastResult.LowCastlevel; return SpellCastResult.LowCastlevel;
//make sure the player has the required herbs in inventory //make sure the player has the required herbs in inventory
if (m_targets.GetItemTarget().GetCount() < 5) if (item.GetCount() < 5)
{
param1 = item.GetEntry();
param2 = 5;
return SpellCastResult.NeedMoreItems; return SpellCastResult.NeedMoreItems;
}
if (!LootStorage.Milling.HaveLootFor(m_targets.GetItemTargetEntry())) if (!LootStorage.Milling.HaveLootFor(m_targets.GetItemTargetEntry()))
return SpellCastResult.CantBeMilled; return SpellCastResult.CantBeMilled;
@@ -7145,7 +7208,7 @@ namespace Game.Spells
return false; return false;
} }
public static implicit operator bool (Spell spell) public static implicit operator bool(Spell spell)
{ {
return spell != null; return spell != null;
} }
+507 -14
View File
@@ -638,32 +638,35 @@ namespace Game.Spells
return IsAffected(affectSpell.SpellFamilyName, mod.mask); return IsAffected(affectSpell.SpellFamilyName, mod.mask);
} }
public bool CanPierceImmuneAura(SpellInfo aura) public bool CanPierceImmuneAura(SpellInfo auraSpellInfo)
{ {
// aura can't be pierced
if (auraSpellInfo == null || auraSpellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return false;
// these spells pierce all avalible spells (Resurrection Sickness for example) // these spells pierce all avalible spells (Resurrection Sickness for example)
if (HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) if (HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return true; return true;
// these spells (Cyclone for example) can pierce all... | ...but not these (Divine shield, Ice block, Cyclone and Banish for example) // Dispels other auras on immunity, check if this spell makes the unit immune to aura
if (HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) if (HasAttribute(SpellAttr1.DispelAurasOnImmunity) && CanSpellProvideImmunityAgainstAura(auraSpellInfo))
&& !(aura != null && (aura.Mechanic == Mechanics.Immune_Shield || aura.Mechanic == Mechanics.Invulnerability || aura.Mechanic == Mechanics.Banish)))
return true; return true;
return false; return false;
} }
public bool CanDispelAura(SpellInfo aura) public bool CanDispelAura(SpellInfo auraSpellInfo)
{ {
// These spells (like Mass Dispel) can dispell all auras
if (HasAttribute(SpellAttr0.UnaffectedByInvulnerability) && !aura.IsDeathPersistent())
return true;
// These auras (like Divine Shield) can't be dispelled // These auras (like Divine Shield) can't be dispelled
if (aura.HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) if (auraSpellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return false; return false;
// These spells (like Mass Dispel) can dispel all auras
if (HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return true;
// These auras (Cyclone for example) are not dispelable // These auras (Cyclone for example) are not dispelable
if (aura.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune)) if (auraSpellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
return false; return false;
return true; return true;
@@ -1204,7 +1207,7 @@ namespace Game.Spells
// if target is magnet (i.e Grounding Totem) the check is skipped // if target is magnet (i.e Grounding Totem) the check is skipped
//if (target.IsMagnet()) //if (target.IsMagnet())
//return true; //return true;
uint creatureType = target.GetCreatureTypeMask(); uint creatureType = target.GetCreatureTypeMask();
return TargetCreatureType == 0 || creatureType == 0 || Convert.ToBoolean(creatureType & TargetCreatureType); return TargetCreatureType == 0 || creatureType == 0 || Convert.ToBoolean(creatureType & TargetCreatureType);
@@ -2017,6 +2020,478 @@ namespace Game.Spells
return 8 * Time.InMilliseconds; return 8 * Time.InMilliseconds;
} }
public void _LoadImmunityInfo()
{
var loadImmunityInfoFn = new Action<SpellEffectInfo>(effectInfo =>
{
uint schoolImmunityMask = 0;
uint applyHarmfulAuraImmunityMask = 0;
uint mechanicImmunityMask = 0;
uint dispelImmunity = 0;
uint damageImmunityMask = 0;
int miscVal = effectInfo.MiscValue;
int amount = effectInfo.CalcValue();
ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo();
switch (effectInfo.ApplyAuraName)
{
case AuraType.MechanicImmunityMask:
{
switch (miscVal)
{
case 96: // Free Friend, Uncontrollable Frenzy, Warlord's Presence
{
mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot);
immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse);
immuneInfo.AuraTypeImmune.Add(AuraType.ModFear);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2);
break;
}
case 1615: // Incite Rage, Wolf Spirit, Overload, Lightning Tendrils
{
switch (Id)
{
case 43292: // Incite Rage
case 49172: // Wolf Spirit
mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot);
immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse);
immuneInfo.AuraTypeImmune.Add(AuraType.ModFear);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2);
goto case 61869;
// no break intended
case 61869: // Overload
case 63481:
case 61887: // Lightning Tendrils
case 63486:
mechanicImmunityMask |= (1 << (int)Mechanics.Interrupt) | (1 << (int)Mechanics.Silence);
immuneInfo.SpellEffectImmune.Add(SpellEffectName.KnockBack);
immuneInfo.SpellEffectImmune.Add(SpellEffectName.KnockBackDest);
break;
default:
break;
}
break;
}
case 679: // Mind Control, Avenging Fury
{
if (Id == 57742) // Avenging Fury
{
mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot);
immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse);
immuneInfo.AuraTypeImmune.Add(AuraType.ModFear);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2);
}
break;
}
case 1557: // Startling Roar, Warlord Roar, Break Bonds, Stormshield
{
if (Id == 64187) // Stormshield
{
mechanicImmunityMask |= (1 << (int)Mechanics.Stun);
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
}
else
{
mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot);
immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse);
immuneInfo.AuraTypeImmune.Add(AuraType.ModFear);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2);
}
break;
}
case 1614: // Fixate
case 1694: // Fixated, Lightning Tendrils
{
immuneInfo.SpellEffectImmune.Add(SpellEffectName.AttackMe);
immuneInfo.AuraTypeImmune.Add(AuraType.ModTaunt);
break;
}
case 1630: // Fervor, Berserk
{
if (Id == 64112) // Berserk
{
immuneInfo.SpellEffectImmune.Add(SpellEffectName.AttackMe);
immuneInfo.AuraTypeImmune.Add(AuraType.ModTaunt);
}
else
{
mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot);
immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse);
immuneInfo.AuraTypeImmune.Add(AuraType.ModFear);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2);
}
break;
}
case 477: // Bladestorm
case 1733: // Bladestorm, Killing Spree
{
if (amount == 0)
{
mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
immuneInfo.SpellEffectImmune.Add(SpellEffectName.KnockBack);
immuneInfo.SpellEffectImmune.Add(SpellEffectName.KnockBackDest);
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot);
immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse);
immuneInfo.AuraTypeImmune.Add(AuraType.ModFear);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2);
}
break;
}
case 878: // Whirlwind, Fog of Corruption, Determination
{
if (Id == 66092) // Determination
{
mechanicImmunityMask |= (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Stun)
| (1 << (int)Mechanics.Disoriented) | (1 << (int)Mechanics.Freeze);
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed);
}
break;
}
default:
break;
}
if (immuneInfo.AuraTypeImmune.Empty())
{
if (miscVal.HasAnyFlag(1 << 10))
immuneInfo.AuraTypeImmune.Add(AuraType.ModStun);
if (miscVal.HasAnyFlag(1 << 1))
immuneInfo.AuraTypeImmune.Add(AuraType.Transform);
// These flag can be recognized wrong:
if (miscVal.HasAnyFlag(1 << 6))
immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed);
if (miscVal.HasAnyFlag(1 << 0))
{
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot);
immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2);
}
if (miscVal.HasAnyFlag(1 << 2))
immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse);
if (miscVal.HasAnyFlag(1 << 9))
immuneInfo.AuraTypeImmune.Add(AuraType.ModFear);
if (miscVal.HasAnyFlag(1 << 7))
immuneInfo.AuraTypeImmune.Add(AuraType.ModDisarm);
}
break;
}
case AuraType.MechanicImmunity:
{
switch (Id)
{
case 34471: // The Beast Within
case 19574: // Bestial Wrath
case 42292: // PvP trinket
case 46227: // Medallion of Immunity
case 59752: // Every Man for Himself
case 53490: // Bullheaded
case 65547: // PvP Trinket
case 134946: // Supremacy of the Alliance
case 134956: // Supremacy of the Horde
case 195710: // Honorable Medallion
case 208683: // Gladiator's Medallion
mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
break;
case 54508: // Demonic Empowerment
mechanicImmunityMask |= (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Root) | (1 << (int)Mechanics.Stun);
break;
default:
if (miscVal < 1)
return;
mechanicImmunityMask |= 1u << miscVal;
break;
}
break;
}
case AuraType.EffectImmunity:
{
immuneInfo.SpellEffectImmune.Add((SpellEffectName)miscVal);
break;
}
case AuraType.StateImmunity:
{
immuneInfo.AuraTypeImmune.Add((AuraType)miscVal);
break;
}
case AuraType.SchoolImmunity:
{
schoolImmunityMask |= (uint)miscVal;
break;
}
case AuraType.ModImmuneAuraApplySchool:
{
applyHarmfulAuraImmunityMask |= (uint)miscVal;
break;
}
case AuraType.DamageImmunity:
{
damageImmunityMask |= (uint)miscVal;
break;
}
case AuraType.DispelImmunity:
{
dispelImmunity = (uint)miscVal;
break;
}
default:
break;
}
immuneInfo.SchoolImmuneMask = schoolImmunityMask;
immuneInfo.ApplyHarmfulAuraImmuneMask = applyHarmfulAuraImmunityMask;
immuneInfo.MechanicImmuneMask = mechanicImmunityMask;
immuneInfo.DispelImmune = dispelImmunity;
immuneInfo.DamageSchoolMask = damageImmunityMask;
});
foreach (var effects in _effects)
{
foreach (SpellEffectInfo effect in effects.Value)
{
if (effect == null)
continue;
loadImmunityInfoFn(effect);
}
}
}
public void ApplyAllSpellImmunitiesTo(Unit target, SpellEffectInfo effect, bool apply)
{
ImmunityInfo immuneInfo = effect.GetImmunityInfo();
uint schoolImmunity = immuneInfo.SchoolImmuneMask;
if (schoolImmunity != 0)
{
target.ApplySpellImmune(Id, SpellImmunity.School, schoolImmunity, apply);
if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity))
{
target.RemoveAppliedAuras(aurApp =>
{
SpellInfo auraSpellInfo = aurApp.GetBase().GetSpellInfo();
return (((uint)auraSpellInfo.GetSchoolMask() & schoolImmunity) != 0 && // Check for school mask
CanDispelAura(auraSpellInfo) &&
(IsPositive() != aurApp.IsPositive()) && // Check spell vs aura possitivity
!auraSpellInfo.IsPassive() && // Don't remove passive auras
auraSpellInfo.Id != Id); // Don't remove self
});
}
}
uint mechanicImmunity = immuneInfo.MechanicImmuneMask;
if (mechanicImmunity != 0)
{
for (uint i = 0; i < (int)Mechanics.Max; ++i)
if (Convert.ToBoolean(mechanicImmunity & (1 << (int)i)))
target.ApplySpellImmune(Id, SpellImmunity.Mechanic, i, apply);
if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity))
target.RemoveAurasWithMechanic(mechanicImmunity, AuraRemoveMode.Default, Id);
}
uint dispelImmunity = immuneInfo.DispelImmune;
if (dispelImmunity != 0)
{
target.ApplySpellImmune(Id, SpellImmunity.Dispel, dispelImmunity, apply);
if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity))
{
target.RemoveAppliedAuras(aurApp =>
{
SpellInfo spellInfo = aurApp.GetBase().GetSpellInfo();
if ((uint)spellInfo.Dispel == dispelImmunity)
return true;
return false;
});
}
}
uint damageImmunity = immuneInfo.DamageSchoolMask;
if (damageImmunity != 0)
target.ApplySpellImmune(Id, SpellImmunity.Damage, damageImmunity, apply);
foreach (AuraType auraType in immuneInfo.AuraTypeImmune)
{
target.ApplySpellImmune(Id, SpellImmunity.State, auraType, apply);
if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity))
target.RemoveAurasByType(auraType);
}
foreach (SpellEffectName effectType in immuneInfo.SpellEffectImmune)
target.ApplySpellImmune(Id, SpellImmunity.Effect, effectType, apply);
}
bool CanSpellProvideImmunityAgainstAura(SpellInfo auraSpellInfo)
{
if (auraSpellInfo == null)
return false;
foreach (SpellEffectInfo effectInfo in GetEffectsForDifficulty(Difficulty.None))
{
if (effectInfo == null)
continue;
ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo();
if (!auraSpellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
{
uint schoolImmunity = immuneInfo.SchoolImmuneMask;
if (schoolImmunity != 0)
if (((uint)auraSpellInfo.SchoolMask & schoolImmunity) != 0)
return true;
}
uint mechanicImmunity = immuneInfo.MechanicImmuneMask;
if (mechanicImmunity != 0)
if ((mechanicImmunity & (1 << (int)auraSpellInfo.Mechanic)) != 0)
return true;
uint dispelImmunity = immuneInfo.DispelImmune;
if (dispelImmunity != 0)
if ((uint)auraSpellInfo.Dispel == dispelImmunity)
return true;
bool immuneToAllEffects = true;
foreach (SpellEffectInfo auraSpellEffectInfo in auraSpellInfo.GetEffectsForDifficulty(Difficulty.None))
{
if (auraSpellEffectInfo == null)
continue;
SpellEffectName effectName = auraSpellEffectInfo.Effect;
if (effectName == 0)
continue;
if (!immuneInfo.SpellEffectImmune.Contains(effectName))
{
immuneToAllEffects = false;
break;
}
uint mechanic = (uint)auraSpellEffectInfo.Mechanic;
if (mechanic != 0)
{
if (!Convert.ToBoolean(immuneInfo.MechanicImmuneMask & (1 << (int)mechanic)))
{
immuneToAllEffects = false;
break;
}
}
if (!auraSpellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
{
AuraType auraName = auraSpellEffectInfo.ApplyAuraName;
if (auraName != 0)
{
bool isImmuneToAuraEffectApply = false;
if (!immuneInfo.AuraTypeImmune.Contains(auraName))
isImmuneToAuraEffectApply = true;
if (!isImmuneToAuraEffectApply && !auraSpellInfo.IsPositiveEffect(auraSpellEffectInfo.EffectIndex) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
{
uint applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask;
if (applyHarmfulAuraImmunityMask != 0)
if (((uint)auraSpellInfo.GetSchoolMask() & applyHarmfulAuraImmunityMask) != 0)
isImmuneToAuraEffectApply = true;
}
if (!isImmuneToAuraEffectApply)
{
immuneToAllEffects = false;
break;
}
}
}
}
if (immuneToAllEffects)
return true;
}
return false;
}
// based on client sub_007FDFA0
public bool CanSpellCastOverrideAuraEffect(AuraEffect aurEff)
{
if (!HasAttribute(SpellAttr1.DispelAurasOnImmunity))
return false;
if (aurEff.GetSpellInfo().HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return false;
foreach (SpellEffectInfo effectInfo in GetEffectsForDifficulty(Difficulty.None))
{
if (effectInfo == null)
continue;
if (effectInfo.Effect != SpellEffectName.ApplyAura)
continue;
uint miscValue = (uint)effectInfo.MiscValue;
switch (effectInfo.ApplyAuraName)
{
case AuraType.StateImmunity:
if (miscValue != (uint)aurEff.GetSpellEffectInfo().ApplyAuraName)
continue;
break;
case AuraType.SchoolImmunity:
case AuraType.ModImmuneAuraApplySchool:
if (aurEff.GetSpellInfo().HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune) || !Convert.ToBoolean((uint)aurEff.GetSpellInfo().SchoolMask & miscValue))
continue;
break;
case AuraType.DispelImmunity:
if (miscValue != (uint)aurEff.GetSpellInfo().Dispel)
continue;
break;
case AuraType.MechanicImmunity:
if (miscValue != (uint)aurEff.GetSpellInfo().Mechanic)
{
if (miscValue != (uint)aurEff.GetSpellEffectInfo().Mechanic)
continue;
}
break;
default:
continue;
}
return true;
}
return false;
}
public float GetMinRange(bool positive = false) public float GetMinRange(bool positive = false)
{ {
if (RangeEntry == null) if (RangeEntry == null)
@@ -2594,8 +3069,8 @@ namespace Game.Spells
var visual = CliDB.SpellXSpellVisualStorage.LookupByKey(GetSpellXSpellVisualId(caster)); var visual = CliDB.SpellXSpellVisualStorage.LookupByKey(GetSpellXSpellVisualId(caster));
if (visual != null) if (visual != null)
{ {
//if (visual->LowViolenceSpellVisualID && forPlayer->GetViolenceLevel() operator 2) //if (visual.LowViolenceSpellVisualID && forPlayer.GetViolenceLevel() operator 2)
// return visual->LowViolenceSpellVisualID; // return visual.LowViolenceSpellVisualID;
return visual.SpellVisualID; return visual.SpellVisualID;
} }
@@ -3213,6 +3688,8 @@ namespace Game.Spells
Scaling.Coefficient = spellEffectScaling != null ? spellEffectScaling.Coefficient : 0.0f; Scaling.Coefficient = spellEffectScaling != null ? spellEffectScaling.Coefficient : 0.0f;
Scaling.Variance = spellEffectScaling != null ? spellEffectScaling.Variance : 0.0f; Scaling.Variance = spellEffectScaling != null ? spellEffectScaling.Variance : 0.0f;
Scaling.ResourceCoefficient = spellEffectScaling != null ? spellEffectScaling.ResourceCoefficient : 0.0f; Scaling.ResourceCoefficient = spellEffectScaling != null ? spellEffectScaling.ResourceCoefficient : 0.0f;
_immunityInfo = new ImmunityInfo();
} }
public bool IsEffect() public bool IsEffect()
@@ -3551,6 +4028,8 @@ namespace Game.Spells
return _data[(int)Effect].UsedTargetObjectType; return _data[(int)Effect].UsedTargetObjectType;
} }
public ImmunityInfo GetImmunityInfo() { return _immunityInfo; }
public class StaticData public class StaticData
{ {
public StaticData(SpellEffectImplicitTargetTypes implicittarget, SpellTargetObjectTypes usedtarget) public StaticData(SpellEffectImplicitTargetTypes implicittarget, SpellTargetObjectTypes usedtarget)
@@ -3853,6 +4332,8 @@ namespace Game.Spells
public float BonusCoefficientFromAP; public float BonusCoefficientFromAP;
public List<Condition> ImplicitTargetConditions; public List<Condition> ImplicitTargetConditions;
public ScalingInfo Scaling; public ScalingInfo Scaling;
ImmunityInfo _immunityInfo;
#endregion #endregion
public struct ScalingInfo public struct ScalingInfo
@@ -4208,5 +4689,17 @@ namespace Game.Spells
public DiminishingLevels DiminishMaxLevel = DiminishingLevels.Immune; public DiminishingLevels DiminishMaxLevel = DiminishingLevels.Immune;
public int DiminishDurationLimit; public int DiminishDurationLimit;
} }
public class ImmunityInfo
{
public uint SchoolImmuneMask;
public uint ApplyHarmfulAuraImmuneMask;
public uint MechanicImmuneMask;
public uint DispelImmune;
public uint DamageSchoolMask;
public List<AuraType> AuraTypeImmune = new List<AuraType>();
public List<SpellEffectName> SpellEffectImmune = new List<SpellEffectName>();
}
} }
+15
View File
@@ -2815,6 +2815,21 @@ namespace Game.Entities
Log.outInfo(LogFilter.ServerLoading, "Loaded SpellInfo diminishing infos in {0} ms", Time.GetMSTimeDiffToNow(oldMSTime)); Log.outInfo(LogFilter.ServerLoading, "Loaded SpellInfo diminishing infos in {0} ms", Time.GetMSTimeDiffToNow(oldMSTime));
} }
public void LoadSpellInfoImmunities()
{
uint oldMSTime = Time.GetMSTime();
foreach (SpellInfo spellInfo in mSpellInfoMap.Values)
{
if (spellInfo == null)
continue;
spellInfo._LoadImmunityInfo();
}
Log.outInfo(LogFilter.ServerLoading, "Loaded SpellInfo immunity infos in {0} ms", Time.GetMSTimeDiffToNow(oldMSTime));
}
public void LoadPetFamilySpellsStore() public void LoadPetFamilySpellsStore()
{ {
Dictionary<uint, SpellLevelsRecord> levelsBySpell = new Dictionary<uint, SpellLevelsRecord>(); Dictionary<uint, SpellLevelsRecord> levelsBySpell = new Dictionary<uint, SpellLevelsRecord>();
+1 -1
View File
@@ -60,7 +60,7 @@ namespace Scripts.Northrend
public npc_mageguard_dalaran(Creature creature) : base(creature) public npc_mageguard_dalaran(Creature creature) : base(creature)
{ {
creature.SetFlag(UnitFields.Flags, UnitFlags.NonAttackable); creature.SetFlag(UnitFields.Flags, UnitFlags.NonAttackable);
creature.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchools.Normal, true); creature.ApplySpellImmune(0, SpellImmunity.Damage, (uint)SpellSchools.Normal, true);
creature.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, true); creature.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, true);
} }