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,
Enraged = 31,
Wounded = 32,
Max = 33,
ImmuneToMovementImpairmentAndLossControlMask = ((1 << Charm) | (1 << Disoriented) |
(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
Unk24 = 0x1000000, // 24
Unk25 = 0x2000000, // 25
Unk26 = 0x4000000, // 26 Unaffected By School Immunity
UnaffectedByAuraSchoolImmune = 0x4000000, // 26 Unaffected By School Immunity
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
TriggeredCanTriggerProc = 0x40000000, // 30 Spell Can Trigger Even If Triggered
FoodBuff = 0x80000000 // 31 Food Or Drink Buff (Like Well Fed)
@@ -1539,7 +1540,7 @@ namespace Framework.Constants
Unk17 = 0x20000, // 17 Only 27965 (Suicide) Spell.
HasChargeEffect = 0x40000, // 18 Only Spells That Have Charge Among Effects.
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
Unk22 = 0x400000, // 22
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)
{
if (victim.IsImmunedToDamage(spellProto))
{
SendSpellDamageImmune(victim, spellProto.Id, false);
return 0;
}
if (victim.IsAIEnabled)
victim.GetAI().DamageTaken(this, ref damage);
+1 -7
View File
@@ -85,7 +85,7 @@ namespace Game.Entities
//Spells
protected Dictionary<CurrentSpellTypes, Spell> m_currentSpells = new Dictionary<CurrentSpellTypes, Spell>((int)CurrentSpellTypes.Max);
Dictionary<SpellValueMod, int> CustomSpellValueMod = new Dictionary<SpellValueMod, int>();
MultiMap<SpellImmunity, SpellImmune> m_spellImmune = new MultiMap<SpellImmunity, SpellImmune>();
MultiMap<uint, uint>[] m_spellImmune = new MultiMap<uint, uint>[(int)SpellImmunity.Max];
uint[] m_interruptMask = new uint[2];
protected int m_procDeep;
bool m_AutoRepeatFirstCast;
@@ -132,12 +132,6 @@ namespace Game.Entities
ushort _meleeAnimKitId;
}
public struct SpellImmune
{
public uint spellType;
public uint spellId;
}
public class DiminishingReturn
{
public DiminishingReturn() { }
+1 -1
View File
@@ -1403,7 +1403,7 @@ namespace Game.Entities
return GetPositionZ() - offset;
}
Unit GetUnitBeingMoved()
public Unit GetUnitBeingMoved()
{
Player player = ToPlayer();
if (player)
+100 -115
View File
@@ -794,20 +794,20 @@ namespace Game.Entities
// Parry
// For spells
// Resist
public SpellMissInfo SpellHitResult(Unit victim, SpellInfo spell, bool CanReflect)
public SpellMissInfo SpellHitResult(Unit victim, SpellInfo spellInfo, bool CanReflect)
{
if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return SpellMissInfo.None;
// Check for immune
if (victim.IsImmunedToSpell(spell))
if (victim.IsImmunedToSpell(spellInfo))
return SpellMissInfo.Immune;
// All positive spells can`t miss
// @todo client not show miss log for this spells - so need find info for this in dbc and use it!
if (spell.IsPositive()
if (spellInfo.IsPositive()
&& (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell
return SpellMissInfo.None;
// Check for immune
if (victim.IsImmunedToDamage(spell))
return SpellMissInfo.Immune;
if (this == victim)
return SpellMissInfo.None;
@@ -822,22 +822,22 @@ namespace Game.Entities
int reflectchance = victim.GetTotalAuraModifier(AuraType.ReflectSpells);
var mReflectSpellsSchool = victim.GetAuraEffectsByType(AuraType.ReflectSpellsSchool);
foreach (var eff in mReflectSpellsSchool)
if (Convert.ToBoolean(eff.GetMiscValue() & (int)spell.GetSchoolMask()))
if (Convert.ToBoolean(eff.GetMiscValue() & (int)spellInfo.GetSchoolMask()))
reflectchance += eff.GetAmount();
if (reflectchance > 0 && RandomHelper.randChance(reflectchance))
return SpellMissInfo.Reflect;
}
switch (spell.DmgClass)
switch (spellInfo.DmgClass)
{
case SpellDmgClass.Ranged:
case SpellDmgClass.Melee:
return MeleeSpellHitResult(victim, spell);
return MeleeSpellHitResult(victim, spellInfo);
case SpellDmgClass.None:
return SpellMissInfo.None;
case SpellDmgClass.Magic:
return MagicSpellHitResult(victim, spell);
return MagicSpellHitResult(victim, spellInfo);
}
return SpellMissInfo.None;
}
@@ -845,11 +845,6 @@ namespace Game.Entities
// Melee based spells hit result calculations
SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo)
{
// Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
// resist and deflect chances
if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return SpellMissInfo.None;
WeaponAttackType attType = WeaponAttackType.BaseAttack;
// Check damage class instead of attack type to correctly handle judgements
@@ -1433,10 +1428,11 @@ namespace Game.Entities
{
Spell spell = m_currentSpells.LookupByKey(CurrentSpellTypes.Channeled);
if (spell)
if (spell.getState() != SpellState.Finished)
return spell.GetSpellInfo().HasAttribute(SpellAttr5.CanChannelWhenMoving) && spell.IsChannelActive();
if (spell.getState() != SpellState.Finished && spell.IsChannelActive())
if (!spell.GetSpellInfo().IsMoveAllowedChannel())
return false;
return false;
return true;
}
bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura)
@@ -1552,24 +1548,35 @@ namespace Game.Entities
SendEnergizeSpellLog(victim, spellId, damage, overEnergize, powerType);
}
public void ApplySpellImmune(uint spellId, SpellImmunity op, object type, bool apply)
public void ApplySpellImmune(uint spellId, SpellImmunity op, SpellSchoolMask type, bool apply)
{
ApplySpellImmune(spellId, op, (uint)type, apply);
}
public void ApplySpellImmune(uint spellId, SpellImmunity op, AuraType type, bool apply)
{
ApplySpellImmune(spellId, op, (uint)type, apply);
}
public void ApplySpellImmune(uint spellId, SpellImmunity op, SpellEffectName type, bool apply)
{
ApplySpellImmune(spellId, op, (uint)type, apply);
}
public void ApplySpellImmune(uint spellId, SpellImmunity op, uint type, bool apply)
{
if (apply)
{
m_spellImmune[op].RemoveAll(p => p.spellType == Convert.ToUInt32(type));
SpellImmune Immune = new SpellImmune();
Immune.spellId = spellId;
Immune.spellType = Convert.ToUInt32(type);
m_spellImmune.Add(op, Immune);
m_spellImmune[(int)op].Add(type, spellId);
}
else
{
foreach (var spell in m_spellImmune[op].ToList())
var bounds = m_spellImmune[(int)op].LookupByKey(type);
foreach (var spell in bounds)
{
if (spell.spellId == spellId && spell.spellType == Convert.ToUInt32(type))
if (spell == spellId)
{
m_spellImmune.Remove(op, spell);
m_spellImmune[(int)op].Remove(type, spell);
break;
}
}
@@ -1581,28 +1588,27 @@ namespace Game.Entities
return false;
// Single spell immunity.
var idList = m_spellImmune.LookupByKey(SpellImmunity.Id);
foreach (var immune in idList)
if (immune.spellType == spellInfo.Id)
return true;
var idList = m_spellImmune[(int)SpellImmunity.Id];
if (idList.ContainsKey(spellInfo.Id))
return true;
if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return false;
if (spellInfo.Dispel != 0)
uint dispel = (uint)spellInfo.Dispel;
if (dispel != 0)
{
var dispelList = m_spellImmune.LookupByKey(SpellImmunity.Dispel);
foreach (var immune in dispelList)
if (immune.spellType == (int)spellInfo.Dispel)
return true;
var dispelList = m_spellImmune[(int)SpellImmunity.Dispel];
if (dispelList.ContainsKey(dispel))
return true;
}
// Spells that don't have effectMechanics.
if (spellInfo.Mechanic != 0)
uint mechanic = (uint)spellInfo.Mechanic;
if (mechanic != 0)
{
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic);
foreach (var immune in mechanicList)
if (immune.spellType == (int)spellInfo.Mechanic)
var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
if (mechanicList.ContainsKey(mechanic))
return true;
}
@@ -1611,7 +1617,7 @@ namespace Game.Entities
{
// State/effect immunities applied by aura expect full spell immunity
// Ignore effects with mechanic, they are supposed to be checked separately
if (effect == null || !effect.IsEffect())
if (effect == null)
continue;
if (!IsImmunedToSpellEffect(spellInfo, effect.EffectIndex))
@@ -1624,13 +1630,13 @@ namespace Game.Entities
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
return true;
if (spellInfo.Id != 42292 && spellInfo.Id != 59752)
if (!spellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) && !spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
{
var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School);
foreach (var immune in schoolList)
var schoolList = m_spellImmune[(int)SpellImmunity.School];
foreach (var pair in schoolList)
{
SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(immune.spellId);
if (Convert.ToBoolean(immune.spellType & (uint)spellInfo.GetSchoolMask())
SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(pair.Value);
if (Convert.ToBoolean(pair.Key & (uint)spellInfo.GetSchoolMask())
&& !(immuneSpellInfo != null && immuneSpellInfo.IsPositive() && spellInfo.IsPositive())
&& !spellInfo.CanPierceImmuneAura(immuneSpellInfo))
return true;
@@ -1642,18 +1648,18 @@ namespace Game.Entities
public uint GetSchoolImmunityMask()
{
uint mask = 0;
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.School);
foreach (var spell in mechanicList)
mask |= spell.spellType;
var mechanicList = m_spellImmune[(int)SpellImmunity.School];
foreach (var pair in mechanicList)
mask |= pair.Key;
return mask;
}
public uint GetMechanicImmunityMask()
{
uint mask = 0;
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic);
foreach (var spell in mechanicList)
mask |= (uint)(1 << (int)spell.spellType);
var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
foreach (var pair in mechanicList)
mask |= (1u << (int)pair.Value);
return mask;
}
@@ -1668,75 +1674,76 @@ namespace Game.Entities
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
uint eff = (uint)effect.Effect;
var effectList = m_spellImmune.LookupByKey(SpellImmunity.Effect);
foreach (var immune in effectList)
if (immune.spellType == eff)
return true;
var effectList = m_spellImmune[(int)SpellImmunity.Effect];
if (effectList.ContainsKey(eff))
return true;
uint mechanic = (uint)effect.Mechanic;
if (mechanic != 0)
{
var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic);
foreach (var immune in mechanicList)
if (immune.spellType == mechanic)
return true;
var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic];
if (mechanicList.ContainsKey(mechanic))
return true;
}
uint aura = (uint)effect.ApplyAuraName;
if (aura != 0)
if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
{
var list = m_spellImmune.LookupByKey(SpellImmunity.State);
foreach (var immune in list)
if (immune.spellType == aura)
if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return true;
// Check for immune to application of harmful magical effects
var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool);
foreach (var immune in immuneAuraApply)
if (spellInfo.Dispel == DispelType.Magic && // Magic debuff
Convert.ToBoolean(immune.GetMiscValue() & (uint)spellInfo.GetSchoolMask()) && // Check school
!spellInfo.IsPositiveEffect(index)) // Harmful
uint aura = (uint)effect.ApplyAuraName;
if (aura != 0)
{
var list = m_spellImmune[(int)SpellImmunity.State];
if (list.ContainsKey(aura))
return true;
if (!spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
{
// Check for immune to application of harmful magical effects
var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool);
foreach (var auraEffect in immuneAuraApply)
if (Convert.ToBoolean(auraEffect.GetMiscValue() & (int)spellInfo.GetSchoolMask()) && // Check school
!spellInfo.IsPositiveEffect(index)) // Harmful
return true;
}
}
}
return false;
}
public bool IsImmunedToDamage(SpellSchoolMask shoolMask)
public bool IsImmunedToDamage(SpellSchoolMask schoolMask)
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School);
var schoolList = m_spellImmune[(int)SpellImmunity.School];
foreach (var immune in schoolList)
if (Convert.ToBoolean(immune.spellType & (uint)shoolMask))
if (Convert.ToBoolean(immune.Key & (uint)schoolMask))
return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
var damageList = m_spellImmune.LookupByKey(SpellImmunity.Damage);
var damageList = m_spellImmune[(int)SpellImmunity.Damage];
foreach (var immune in damageList)
if (Convert.ToBoolean(immune.spellType & (uint)shoolMask))
if (Convert.ToBoolean(immune.Key & (uint)schoolMask))
return true;
return false;
}
public bool IsImmunedToDamage(SpellInfo spellInfo)
{
if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
if (spellInfo == null)
return false;
uint shoolMask = (uint)spellInfo.GetSchoolMask();
if (spellInfo.Id != 42292 && spellInfo.Id != 59752)
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School);
foreach (var immune in schoolList)
if (Convert.ToBoolean(immune.spellType & shoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(immune.spellId)))
return true;
}
if (spellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
return false;
uint schoolMask = (uint)spellInfo.GetSchoolMask();
// If m_immuneToSchool type contain this school type, IMMUNE damage.
var schoolList = m_spellImmune[(int)SpellImmunity.School];
foreach (var pair in schoolList)
if (Convert.ToBoolean(pair.Key & schoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(pair.Value)))
return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
var damageList = m_spellImmune.LookupByKey(SpellImmunity.Damage);
var damageList = m_spellImmune[(int)SpellImmunity.Damage];
foreach (var immune in damageList)
if (Convert.ToBoolean(immune.spellType & shoolMask))
if (Convert.ToBoolean(immune.Key & schoolMask))
return true;
return false;
@@ -2173,7 +2180,7 @@ namespace Game.Entities
bool isSpellBlocked(Unit victim, SpellInfo spellProto, WeaponAttackType attackType = WeaponAttackType.BaseAttack)
{
// These spells can't be blocked
if (spellProto != null && spellProto.HasAttribute(SpellAttr0.ImpossibleDodgeParryBlock))
if (spellProto != null && (spellProto.HasAttribute(SpellAttr0.ImpossibleDodgeParryBlock) || spellProto.HasAttribute(SpellAttr3.IgnoreHitResult)))
return false;
// Can't block when casting/controlled
@@ -2657,28 +2664,6 @@ namespace Game.Entities
return null;
}
public void ApplySpellDispelImmunity(SpellInfo spellProto, DispelType type, bool apply)
{
ApplySpellImmune(spellProto.Id, SpellImmunity.Dispel, type, apply);
if (apply && spellProto.HasAttribute(SpellAttr1.DispelAurasOnImmunity))
{
// Create dispel mask by dispel type
uint dispelMask = SpellInfo.GetDispelMask(type);
// Dispel all existing auras vs current dispel type
var auras = GetAppliedAuras();
foreach (var pair in auras)
{
SpellInfo spell = pair.Value.GetBase().GetSpellInfo();
if ((spell.GetDispelMask() & dispelMask) != 0)
{
// Dispel aura
RemoveAura(pair);
}
}
}
}
public DiminishingLevels GetDiminishing(DiminishingGroup group)
{
DiminishingReturn diminish = m_Diminishing[(int)group];
+3
View File
@@ -54,6 +54,9 @@ namespace Game.Entities
m_modAttackSpeedPct = new float[] { 1.0f, 1.0f, 1.0f };
m_deathState = DeathState.Alive;
for (byte i = 0; i < (int)SpellImmunity.Max; ++i)
m_spellImmune[i] = new MultiMap<uint, uint>();
for (byte i = 0; i < (int)UnitMods.End; ++i)
m_auraModifiersGroup[i] = new float[] { 0.0f, 100.0f, 1.0f, 0.0f, 1.0f };
+2 -2
View File
@@ -151,8 +151,8 @@ namespace Game.Entities
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.SchoolImmunity, true);
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.ModUnattackable, true);
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.SchoolAbsorb, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, Mechanics.Shield, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, Mechanics.Immune_Shield, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, (uint)Mechanics.Shield, true);
_me.ApplySpellImmune(0, SpellImmunity.Mechanic, (uint)Mechanics.Immune_Shield, true);
// ... Resistance, Split damage, Change stats ...
_me.ApplySpellImmune(0, SpellImmunity.State, AuraType.DamageShield, true);
+3
View File
@@ -377,6 +377,9 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Loading SpellInfo diminishing infos...");
Global.SpellMgr.LoadSpellInfoDiminishing();
Log.outInfo(LogFilter.ServerLoading, "Loading SpellInfo immunity infos...");
Global.SpellMgr.LoadSpellInfoImmunities();
Log.outInfo(LogFilter.ServerLoading, "Loading PetFamilySpellsStore Data...");
Global.SpellMgr.LoadPetFamilySpellsStore();
+12 -295
View File
@@ -2703,7 +2703,7 @@ namespace Game.Spells
{
//Players on flying mounts must be immune to polymorph
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)
if (apply && target.HasAuraEffect(42016, 0) && target.GetMountID() != 0)
@@ -2767,228 +2767,13 @@ namespace Game.Spells
/*** IMMUNITY ***/
/*********************************************************/
[AuraEffectHandler(AuraType.MechanicImmunityMask)]
void HandleModStateImmunityMask(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
void HandleModMechanicImmunityMask(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply)
{
if (!mode.HasAnyFlag(AuraEffectHandleModes.Real))
return;
Unit target = aurApp.GetTarget();
List<AuraType> aura_immunity_list = new List<AuraType>();
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);
}
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
[AuraEffectHandler(AuraType.MechanicImmunity)]
@@ -2998,52 +2783,7 @@ namespace Game.Spells
return;
Unit target = aurApp.GetTarget();
uint mechanic;
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());
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
[AuraEffectHandler(AuraType.EffectImmunity)]
@@ -3053,8 +2793,7 @@ namespace Game.Spells
return;
Unit target = aurApp.GetTarget();
target.ApplySpellImmune(GetId(), SpellImmunity.Effect, GetMiscValue(), apply);
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
// when removing flag aura, handle flag drop
Player player = target.ToPlayer();
@@ -3078,11 +2817,7 @@ namespace Game.Spells
return;
Unit target = aurApp.GetTarget();
target.ApplySpellImmune(GetId(), SpellImmunity.State, GetMiscValue(), apply);
if (apply && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity))
target.RemoveAurasByType((AuraType)GetMiscValue(), ObjectGuid.Empty, GetBase());
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
[AuraEffectHandler(AuraType.SchoolImmunity)]
@@ -3092,8 +2827,7 @@ namespace Game.Spells
return;
Unit target = aurApp.GetTarget();
target.ApplySpellImmune(GetId(), SpellImmunity.School, (uint)GetMiscValue(), (apply));
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
if (GetSpellInfo().Mechanic == Mechanics.Banish)
{
@@ -3103,9 +2837,9 @@ namespace Game.Spells
{
bool banishFound = false;
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;
break;
@@ -3124,21 +2858,6 @@ namespace Game.Spells
if (GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity)
&& GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield))
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)]
@@ -3148,8 +2867,7 @@ namespace Game.Spells
return;
Unit target = aurApp.GetTarget();
target.ApplySpellImmune(GetId(), SpellImmunity.Damage, (uint)GetMiscValue(), apply);
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
[AuraEffectHandler(AuraType.DispelImmunity)]
@@ -3159,8 +2877,7 @@ namespace Game.Spells
return;
Unit target = aurApp.GetTarget();
target.ApplySpellDispelImmunity(m_spellInfo, (DispelType)GetMiscValue(), (apply));
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
}
/*********************************************************/
@@ -4608,7 +4325,7 @@ namespace Game.Spells
{
// Recently Bandaged
case 11196:
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, GetMiscValue(), apply);
target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, (uint)GetMiscValue(), apply);
break;
// Unstable Power
case 24658:
+284 -221
View File
@@ -2091,7 +2091,7 @@ namespace Game.Spells
return SpellMissInfo.Evade;
// 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;
// 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)
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
// 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)
@@ -2548,7 +2549,10 @@ namespace Game.Spells
m_caster.ToPlayer().SetSpellModTakingSpell(this, false);
}
SendCastResult(result);
if (param1 != 0 || param2 != 0)
SendCastResult(result, param1, param2);
else
SendCastResult(result);
finish(false);
return;
@@ -2749,10 +2753,11 @@ namespace Game.Spells
// skip check if done already (for instant cast spells for example)
if (!skipCheck)
{
SpellCastResult castResult = CheckCast(false);
uint param1 = 0, param2 = 0;
SpellCastResult castResult = CheckCast(false, ref param1, ref param2);
if (castResult != SpellCastResult.SpellCastOk)
{
SendCastResult(castResult);
SendCastResult(castResult, param1, param2);
SendInterrupted(0);
//restore spell mods
if (m_caster.IsTypeId(TypeId.Player))
@@ -3316,7 +3321,7 @@ namespace Game.Spells
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.SpellID = (int)spellInfo.Id;
@@ -3325,112 +3330,183 @@ namespace Game.Spells
switch (result)
{
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;
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;
case SpellCastResult.RequiresArea: // AreaTable.dbc id
// hardcode areas limitation case
switch (spellInfo.Id)
if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
{
case 41617: // Cenarion Mana Salve
case 41619: // Cenarion Healing Salve
packet.FailedArg1 = 3905;
break;
case 41618: // Bottled Nethergon Energy
case 41620: // Bottled Nethergon Vapor
packet.FailedArg1 = 3842;
break;
case 45373: // Bloodberry Elixir
packet.FailedArg1 = 4075;
break;
default: // default case (don't must be)
packet.FailedArg1 = 0;
break;
// hardcode areas limitation case
switch (spellInfo.Id)
{
case 41617: // Cenarion Mana Salve
case 41619: // Cenarion Healing Salve
packet.FailedArg1 = 3905;
break;
case 41618: // Bottled Nethergon Energy
case 41620: // Bottled Nethergon Vapor
packet.FailedArg1 = 3842;
break;
case 45373: // Bloodberry Elixir
packet.FailedArg1 = 4075;
break;
default: // default case (don't must be)
packet.FailedArg1 = 0;
break;
}
}
break;
case SpellCastResult.Totems:
if (spellInfo.Totem[0] != 0)
packet.FailedArg1 = (int)spellInfo.Totem[0];
if (spellInfo.Totem[1] != 0)
packet.FailedArg2 = (int)spellInfo.Totem[1];
if (param1.HasValue)
{
packet.FailedArg1 = (int)param1;
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;
case SpellCastResult.TotemCategory:
if (spellInfo.TotemCategory[0] != 0)
packet.FailedArg1 = (int)spellInfo.TotemCategory[0];
if (spellInfo.TotemCategory[1] != 0)
packet.FailedArg2 = (int)spellInfo.TotemCategory[1];
if (param1.HasValue)
{
packet.FailedArg1 = (int)param1;
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;
case SpellCastResult.EquippedItemClass:
case SpellCastResult.EquippedItemClassMainhand:
case SpellCastResult.EquippedItemClassOffhand:
packet.FailedArg1 = (int)spellInfo.EquippedItemClass;
packet.FailedArg2 = spellInfo.EquippedItemSubClassMask;
if (param1.HasValue && param2.HasValue)
{
packet.FailedArg1 = (int)param1;
packet.FailedArg2 = (int)param2;
}
else
{
packet.FailedArg1 = (int)spellInfo.EquippedItemClass;
packet.FailedArg2 = spellInfo.EquippedItemSubClassMask;
}
break;
case SpellCastResult.TooManyOfItem:
{
uint item = 0;
foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(caster.GetMap().GetDifficultyID()))
if (effect.ItemType != 0)
item = effect.ItemType;
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item);
if (proto != null && proto.GetItemLimitCategory() != 0)
packet.FailedArg1 = (int)proto.GetItemLimitCategory();
if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
{
uint item = 0;
foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(caster.GetMap().GetDifficultyID()))
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;
}
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;
case SpellCastResult.NeedExoticAmmo:
packet.FailedArg1 = spellInfo.EquippedItemSubClassMask; // seems correct...
if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = spellInfo.EquippedItemSubClassMask; // seems correct...
break;
case SpellCastResult.NeedMoreItems:
packet.FailedArg1 = 0; // Item id
packet.FailedArg2 = 0; // Item count?
if (param1.HasValue && param2.HasValue)
{
packet.FailedArg1 = (int)param1;
packet.FailedArg2 = (int)param2;
}
else
{
packet.FailedArg1 = 0; // Item id
packet.FailedArg2 = 0; // Item count?
}
break;
case SpellCastResult.MinSkill:
packet.FailedArg1 = 0; // SkillLine.dbc id
packet.FailedArg2 = 0; // required skill value
if (param1.HasValue && param2.HasValue)
{
packet.FailedArg1 = (int)param1;
packet.FailedArg2 = (int)param2;
}
else
{
packet.FailedArg1 = 0; // SkillLine.dbc id
packet.FailedArg2 = 0; // required skill value
}
break;
case SpellCastResult.FishingTooLow:
packet.FailedArg1 = 0; // required fishing skill
if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = 0; // required fishing skill
break;
case SpellCastResult.CustomError:
packet.FailedArg1 = (int)customError;
break;
case SpellCastResult.Silenced:
packet.FailedArg1 = 0; // Unknown
if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
packet.FailedArg1 = 0; // Unknown
break;
case SpellCastResult.Reagents:
{
uint missingItem = 0;
for (uint i = 0; i < SpellConst.MaxReagents; i++)
if (param1.HasValue)
packet.FailedArg1 = (int)param1;
else
{
if (spellInfo.Reagent[i] <= 0)
continue;
uint itemid = (uint)spellInfo.Reagent[i];
uint itemcount = spellInfo.ReagentCount[i];
if (!caster.HasItemCount(itemid, itemcount))
uint missingItem = 0;
for (uint i = 0; i < SpellConst.MaxReagents; i++)
{
missingItem = itemid;
break;
}
}
if (spellInfo.Reagent[i] <= 0)
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;
}
case SpellCastResult.CantUntalent:
{
if (misc != null)
{
TalentRecord talent = CliDB.TalentStorage.LookupByKey(misc[0]);
if (talent != null)
packet.FailedArg1 = (int)talent.SpellID;
}
Contract.Assert(param1.HasValue);
packet.FailedArg1 = (int)param1;
break;
}
// 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)
return;
@@ -3447,7 +3523,7 @@ namespace Game.Spells
if (!m_caster.IsTypeId(TypeId.Player))
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;
if (_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.DontReportCastError))
@@ -3455,11 +3531,11 @@ namespace Game.Spells
CastFailed castFailed = new CastFailed();
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);
}
public void SendPetCastResult(SpellCastResult result)
public void SendPetCastResult(SpellCastResult result, uint? param1 = null, uint? param2 = null)
{
if (result == SpellCastResult.SpellCastOk)
return;
@@ -3472,18 +3548,18 @@ namespace Game.Spells
result = SpellCastResult.DontReport;
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);
}
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)
return;
CastFailed packet = new CastFailed();
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);
}
@@ -4329,6 +4405,12 @@ namespace Game.Spells
}
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;
// check death state
@@ -4395,13 +4477,15 @@ namespace Game.Spells
bool checkForm = true;
// Ignore form req aura
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;
checkForm = false;
break;
}
if (checkForm)
{
// 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)
if (!m_spellInfo.IsPassive())
{
castResult = CheckItems();
castResult = CheckItems(ref param1, ref param2);
if (castResult != SpellCastResult.SpellCastOk)
return castResult;
}
@@ -4650,7 +4734,7 @@ namespace Game.Spells
if (!Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreCasterAuras))
{
castResult = CheckCasterAuras();
castResult = CheckCasterAuras(ref param1);
if (castResult != SpellCastResult.SpellCastOk)
return castResult;
}
@@ -4909,7 +4993,7 @@ namespace Game.Spells
break;
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))
return SpellCastResult.BadTargets;
@@ -5139,7 +5223,10 @@ namespace Game.Spells
if (talent == null)
return SpellCastResult.DontReport;
if (m_caster.GetSpellHistory().HasCooldown(talent.SpellID))
{
param1 = talent.SpellID;
return SpellCastResult.CantUntalent;
}
break;
}
case SpellEffectName.GiveArtifactPower:
@@ -5362,146 +5449,109 @@ namespace Game.Spells
return CheckCast(true);
}
SpellCastResult CheckCasterAuras()
SpellCastResult CheckCasterAuras(ref uint param1)
{
// spells totally immuned to caster auras (wsg flag drop, give marks etc)
if (m_spellInfo.HasAttribute(SpellAttr6.IgnoreCasterAuras))
return SpellCastResult.SpellCastOk;
int school_immune = 0;
uint mechanic_immune = 0;
uint dispel_immune = 0;
// 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))
bool usableWhileStunned = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileStunned);
bool usableWhileFeared = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileFeared);
bool usableWhileConfused = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileConfused);
if (m_spellInfo.HasAttribute(SpellAttr7.UsableInStunFearConfusion))
{
foreach (SpellEffectInfo effect in GetEffects())
{
if (effect == null)
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;
usableWhileStunned = true;
usableWhileFeared = true;
usableWhileConfused = true;
}
bool usableInStun = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileStunned);
// Check whether the cast should be prevented by any state you might have.
SpellCastResult prevented_reason = SpellCastResult.SpellCastOk;
// Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out
UnitFlags unitflag = (UnitFlags)m_caster.GetUInt32Value(UnitFields.Flags); // Get unit state
if (Convert.ToBoolean(unitflag & UnitFlags.Stunned))
SpellCastResult result = SpellCastResult.SpellCastOk;
// Get unit state
UnitFlags unitflag = (UnitFlags)m_caster.GetUInt32Value(UnitFields.Flags);
if (!m_caster.GetCharmerGUID().IsEmpty())
{
// spell is usable while stunned, check if caster has allowed stun auras, another stun types must prevent cast spell
if (usableInStun)
{
uint allowedStunMask =
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;
Unit charmer = m_caster.GetCharmer();
if (charmer)
if (charmer.GetUnitBeingMoved() != m_caster && CheckCasterNotImmunedCharmAuras(ref param1))
result = SpellCastResult.Charmed;
}
else if (unitflag.HasAnyFlag(UnitFlags.Confused) && !m_spellInfo.HasAttribute(SpellAttr5.UsableWhileConfused))
prevented_reason = SpellCastResult.Confused;
else if (unitflag.HasAnyFlag(UnitFlags.Fleeing) && !m_spellInfo.HasAttribute(SpellAttr5.UsableWhileFeared))
prevented_reason = SpellCastResult.Fleeing;
else if (unitflag.HasAnyFlag(UnitFlags.Silenced) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence))
prevented_reason = SpellCastResult.Silenced;
else if (unitflag.HasAnyFlag(UnitFlags.Pacified) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Pacify))
prevented_reason = SpellCastResult.Pacified;
else if (unitflag.HasAnyFlag(UnitFlags.Stunned) && !usableWhileStunned && CheckCasterNotImmunedStunAuras(ref param1))
result = SpellCastResult.Stunned;
else if (unitflag.HasAnyFlag(UnitFlags.Silenced) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence) && CheckCasterNotImmunedSilenceAuras(ref param1))
result = SpellCastResult.Silenced;
else if (unitflag.HasAnyFlag(UnitFlags.Pacified) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Pacify) && CheckCasterNotImmunedPacifyAuras(ref param1))
result = SpellCastResult.Pacified;
else if (unitflag.HasAnyFlag(UnitFlags.Fleeing) && !usableWhileFeared && CheckCasterNotImmunedFearAuras(ref param1))
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))
prevented_reason = SpellCastResult.NoActions;
result = SpellCastResult.NoActions;
// Attr must make flag drop spell totally immune from all effects
if (prevented_reason != SpellCastResult.SpellCastOk)
{
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;
}
if (result != SpellCastResult.SpellCastOk)
return (param1 != 0) ? SpellCastResult.PreventedByMechanic : result;
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()
{
bool isRatedBattleground = false; // NYI
@@ -5727,13 +5777,15 @@ namespace Game.Spells
return SpellCastResult.SpellCastOk;
}
SpellCastResult CheckItems()
SpellCastResult CheckItems(ref uint param1, ref uint param2)
{
Player player = m_caster.ToPlayer();
if (!player)
return SpellCastResult.SpellCastOk;
if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreItemCheck))
return SpellCastResult.SpellCastOk;
if (m_CastItem == null)
{
if (!m_castItemGUID.IsEmpty())
@@ -5809,13 +5861,11 @@ namespace Game.Spells
// check target item
if (!m_targets.GetItemTargetGUID().IsEmpty())
{
if (!m_caster.IsTypeId(TypeId.Player))
return SpellCastResult.BadTargets;
if (m_targets.GetItemTarget() == null)
Item item = m_targets.GetItemTarget();
if (item == null)
return SpellCastResult.ItemGone;
if (!m_targets.GetItemTarget().IsFitToSpellRequirements(m_spellInfo))
if (!item.IsFitToSpellRequirements(m_spellInfo))
return SpellCastResult.EquippedItemClass;
}
// if not item target then required item must be equipped
@@ -5868,7 +5918,10 @@ namespace Game.Spells
}
}
if (!player.HasItemCount(itemid, itemcount))
{
param1 = itemid;
return SpellCastResult.Reagents;
}
}
}
@@ -6073,21 +6126,26 @@ namespace Game.Spells
}
case SpellEffectName.Prospecting:
{
if (m_targets.GetItemTarget() == null)
Item item = m_targets.GetItemTarget();
if (!item)
return SpellCastResult.CantBeProspected;
//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;
//prevent prospecting in trade slot
if (m_targets.GetItemTarget().GetOwnerGUID() != m_caster.GetGUID())
if (item.GetOwnerGUID() != m_caster.GetGUID())
return SpellCastResult.CantBeProspected;
//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))
return SpellCastResult.LowCastlevel;
//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;
}
if (!LootStorage.Prospecting.HaveLootFor(m_targets.GetItemTargetEntry()))
return SpellCastResult.CantBeProspected;
@@ -6096,21 +6154,26 @@ namespace Game.Spells
}
case SpellEffectName.Milling:
{
if (m_targets.GetItemTarget() == null)
Item item = m_targets.GetItemTarget();
if (!item)
return SpellCastResult.CantBeMilled;
//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;
//prevent milling in trade slot
if (m_targets.GetItemTarget().GetOwnerGUID() != m_caster.GetGUID())
if (item.GetOwnerGUID() != m_caster.GetGUID())
return SpellCastResult.CantBeMilled;
//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))
return SpellCastResult.LowCastlevel;
//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;
}
if (!LootStorage.Milling.HaveLootFor(m_targets.GetItemTargetEntry()))
return SpellCastResult.CantBeMilled;
@@ -7145,7 +7208,7 @@ namespace Game.Spells
return false;
}
public static implicit operator bool (Spell spell)
public static implicit operator bool(Spell spell)
{
return spell != null;
}
+507 -14
View File
@@ -638,32 +638,35 @@ namespace Game.Spells
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)
if (HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
return true;
// these spells (Cyclone for example) can pierce all... | ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
if (HasAttribute(SpellAttr1.UnaffectedBySchoolImmune)
&& !(aura != null && (aura.Mechanic == Mechanics.Immune_Shield || aura.Mechanic == Mechanics.Invulnerability || aura.Mechanic == Mechanics.Banish)))
// Dispels other auras on immunity, check if this spell makes the unit immune to aura
if (HasAttribute(SpellAttr1.DispelAurasOnImmunity) && CanSpellProvideImmunityAgainstAura(auraSpellInfo))
return true;
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
if (aura.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
if (auraSpellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
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
if (aura.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune))
if (auraSpellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune))
return false;
return true;
@@ -1204,7 +1207,7 @@ namespace Game.Spells
// if target is magnet (i.e Grounding Totem) the check is skipped
//if (target.IsMagnet())
//return true;
//return true;
uint creatureType = target.GetCreatureTypeMask();
return TargetCreatureType == 0 || creatureType == 0 || Convert.ToBoolean(creatureType & TargetCreatureType);
@@ -2017,6 +2020,478 @@ namespace Game.Spells
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)
{
if (RangeEntry == null)
@@ -2594,8 +3069,8 @@ namespace Game.Spells
var visual = CliDB.SpellXSpellVisualStorage.LookupByKey(GetSpellXSpellVisualId(caster));
if (visual != null)
{
//if (visual->LowViolenceSpellVisualID && forPlayer->GetViolenceLevel() operator 2)
// return visual->LowViolenceSpellVisualID;
//if (visual.LowViolenceSpellVisualID && forPlayer.GetViolenceLevel() operator 2)
// return visual.LowViolenceSpellVisualID;
return visual.SpellVisualID;
}
@@ -3213,6 +3688,8 @@ namespace Game.Spells
Scaling.Coefficient = spellEffectScaling != null ? spellEffectScaling.Coefficient : 0.0f;
Scaling.Variance = spellEffectScaling != null ? spellEffectScaling.Variance : 0.0f;
Scaling.ResourceCoefficient = spellEffectScaling != null ? spellEffectScaling.ResourceCoefficient : 0.0f;
_immunityInfo = new ImmunityInfo();
}
public bool IsEffect()
@@ -3551,6 +4028,8 @@ namespace Game.Spells
return _data[(int)Effect].UsedTargetObjectType;
}
public ImmunityInfo GetImmunityInfo() { return _immunityInfo; }
public class StaticData
{
public StaticData(SpellEffectImplicitTargetTypes implicittarget, SpellTargetObjectTypes usedtarget)
@@ -3853,6 +4332,8 @@ namespace Game.Spells
public float BonusCoefficientFromAP;
public List<Condition> ImplicitTargetConditions;
public ScalingInfo Scaling;
ImmunityInfo _immunityInfo;
#endregion
public struct ScalingInfo
@@ -4208,5 +4689,17 @@ namespace Game.Spells
public DiminishingLevels DiminishMaxLevel = DiminishingLevels.Immune;
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));
}
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()
{
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)
{
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);
}