Files
CypherCore/Source/Game/Spells/SpellInfo.cs
T

5173 lines
276 KiB
C#

// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants;
using Framework.Dynamic;
using Game.BattleGrounds;
using Game.Conditions;
using Game.DataStorage;
using Game.Entities;
using Game.Maps;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Framework.Collections;
namespace Game.Spells
{
public class SpellInfo
{
public SpellInfo(SpellNameRecord spellName, Difficulty difficulty, SpellInfoLoadHelper data)
{
Id = spellName.Id;
Difficulty = difficulty;
foreach (SpellEffectRecord spellEffect in data.Effects)
{
if (spellEffect == null)
continue;
_effects.EnsureWritableListIndex((uint)spellEffect.EffectIndex, new SpellEffectInfo(this));
_effects[spellEffect.EffectIndex] = new SpellEffectInfo(this, spellEffect);
}
// Correct EffectIndex for blank effects
for (int i = 0; i < _effects.Count; ++i)
_effects[i].EffectIndex = (uint)i;
SpellName = spellName.Name;
SpellMiscRecord _misc = data.Misc;
if (_misc != null)
{
Attributes = (SpellAttr0)_misc.Attributes[0];
AttributesEx = (SpellAttr1)_misc.Attributes[1];
AttributesEx2 = (SpellAttr2)_misc.Attributes[2];
AttributesEx3 = (SpellAttr3)_misc.Attributes[3];
AttributesEx4 = (SpellAttr4)_misc.Attributes[4];
AttributesEx5 = (SpellAttr5)_misc.Attributes[5];
AttributesEx6 = (SpellAttr6)_misc.Attributes[6];
AttributesEx7 = (SpellAttr7)_misc.Attributes[7];
AttributesEx8 = (SpellAttr8)_misc.Attributes[8];
AttributesEx9 = (SpellAttr9)_misc.Attributes[9];
AttributesEx10 = (SpellAttr10)_misc.Attributes[10];
AttributesEx11 = (SpellAttr11)_misc.Attributes[11];
AttributesEx12 = (SpellAttr12)_misc.Attributes[12];
AttributesEx13 = (SpellAttr13)_misc.Attributes[13];
AttributesEx14 = (SpellAttr14)_misc.Attributes[14];
CastTimeEntry = CliDB.SpellCastTimesStorage.LookupByKey(_misc.CastingTimeIndex);
DurationEntry = CliDB.SpellDurationStorage.LookupByKey(_misc.DurationIndex);
RangeEntry = CliDB.SpellRangeStorage.LookupByKey(_misc.RangeIndex);
Speed = _misc.Speed;
LaunchDelay = _misc.LaunchDelay;
SchoolMask = (SpellSchoolMask)_misc.SchoolMask;
IconFileDataId = _misc.SpellIconFileDataID;
ActiveIconFileDataId = _misc.ActiveIconFileDataID;
ContentTuningId = _misc.ContentTuningID;
ShowFutureSpellPlayerConditionID = (uint)_misc.ShowFutureSpellPlayerConditionID;
}
// SpellScalingEntry
SpellScalingRecord _scaling = data.Scaling;
if (_scaling != null)
{
Scaling.MinScalingLevel = _scaling.MinScalingLevel;
Scaling.MaxScalingLevel = _scaling.MaxScalingLevel;
Scaling.ScalesFromItemLevel = _scaling.ScalesFromItemLevel;
}
// SpellAuraOptionsEntry
SpellAuraOptionsRecord _options = data.AuraOptions;
if (_options != null)
{
ProcFlags = new ProcFlagsInit(_options.ProcTypeMask);
ProcChance = _options.ProcChance;
ProcCharges = (uint)_options.ProcCharges;
ProcCooldown = _options.ProcCategoryRecovery;
StackAmount = _options.CumulativeAura;
SpellProcsPerMinuteRecord _ppm = CliDB.SpellProcsPerMinuteStorage.LookupByKey(_options.SpellProcsPerMinuteID);
if (_ppm != null)
{
ProcBasePPM = _ppm.BaseProcRate;
ProcPPMMods = Global.DB2Mgr.GetSpellProcsPerMinuteMods(_ppm.Id);
}
}
// SpellAuraRestrictionsEntry
SpellAuraRestrictionsRecord _aura = data.AuraRestrictions;
if (_aura != null)
{
CasterAuraState = (AuraStateType)_aura.CasterAuraState;
TargetAuraState = (AuraStateType)_aura.TargetAuraState;
ExcludeCasterAuraState = (AuraStateType)_aura.ExcludeCasterAuraState;
ExcludeTargetAuraState = (AuraStateType)_aura.ExcludeTargetAuraState;
CasterAuraSpell = _aura.CasterAuraSpell;
TargetAuraSpell = _aura.TargetAuraSpell;
ExcludeCasterAuraSpell = _aura.ExcludeCasterAuraSpell;
ExcludeTargetAuraSpell = _aura.ExcludeTargetAuraSpell;
CasterAuraType = (AuraType)_aura.CasterAuraType;
TargetAuraType = (AuraType)_aura.TargetAuraType;
ExcludeCasterAuraType = (AuraType)_aura.ExcludeCasterAuraType;
ExcludeTargetAuraType = (AuraType)_aura.ExcludeTargetAuraType;
}
RequiredAreasID = -1;
// SpellCastingRequirementsEntry
SpellCastingRequirementsRecord _castreq = data.CastingRequirements;
if (_castreq != null)
{
RequiresSpellFocus = _castreq.RequiresSpellFocus;
FacingCasterFlags = _castreq.FacingCasterFlags;
RequiredAreasID = _castreq.RequiredAreasID;
}
// SpellCategoriesEntry
SpellCategoriesRecord _categorie = data.Categories;
if (_categorie != null)
{
CategoryId = _categorie.Category;
Dispel = (DispelType)_categorie.DispelType;
Mechanic = (Mechanics)_categorie.Mechanic;
StartRecoveryCategory = _categorie.StartRecoveryCategory;
DmgClass = (SpellDmgClass)_categorie.DefenseType;
PreventionType = (SpellPreventionType)_categorie.PreventionType;
ChargeCategoryId = _categorie.ChargeCategory;
}
// SpellClassOptionsEntry
SpellFamilyFlags = new FlagArray128();
SpellClassOptionsRecord _class = data.ClassOptions;
if (_class != null)
{
SpellFamilyName = (SpellFamilyNames)_class.SpellClassSet;
SpellFamilyFlags = _class.SpellClassMask;
}
// SpellCooldownsEntry
SpellCooldownsRecord _cooldowns = data.Cooldowns;
if (_cooldowns != null)
{
RecoveryTime = _cooldowns.RecoveryTime;
CategoryRecoveryTime = _cooldowns.CategoryRecoveryTime;
StartRecoveryTime = _cooldowns.StartRecoveryTime;
CooldownAuraSpellId = _cooldowns.AuraSpellID;
}
EquippedItemClass = ItemClass.None;
EquippedItemSubClassMask = 0;
EquippedItemInventoryTypeMask = 0;
// SpellEmpowerStageEntry
foreach (var stage in data.EmpowerStages)
EmpowerStageThresholds.Add(TimeSpan.FromMilliseconds(stage.DurationMs));
// SpellEquippedItemsEntry
SpellEquippedItemsRecord _equipped = data.EquippedItems;
if (_equipped != null)
{
EquippedItemClass = (ItemClass)_equipped.EquippedItemClass;
EquippedItemSubClassMask = _equipped.EquippedItemSubclass;
EquippedItemInventoryTypeMask = _equipped.EquippedItemInvTypes;
}
// SpellInterruptsEntry
SpellInterruptsRecord _interrupt = data.Interrupts;
if (_interrupt != null)
{
InterruptFlags = (SpellInterruptFlags)_interrupt.InterruptFlags;
AuraInterruptFlags = (SpellAuraInterruptFlags)_interrupt.AuraInterruptFlags[0];
AuraInterruptFlags2 = (SpellAuraInterruptFlags2)_interrupt.AuraInterruptFlags[1];
ChannelInterruptFlags = (SpellAuraInterruptFlags)_interrupt.ChannelInterruptFlags[0];
ChannelInterruptFlags2 = (SpellAuraInterruptFlags2)_interrupt.ChannelInterruptFlags[1];
}
foreach (var label in data.Labels)
Labels.Add(label.LabelID);
// SpellLevelsEntry
SpellLevelsRecord _levels = data.Levels;
if (_levels != null)
{
MaxLevel = _levels.MaxLevel;
BaseLevel = _levels.BaseLevel;
SpellLevel = _levels.SpellLevel;
}
// SpellPowerEntry
PowerCosts = data.Powers;
// SpellReagentsEntry
SpellReagentsRecord _reagents = data.Reagents;
if (_reagents != null)
{
for (var i = 0; i < SpellConst.MaxReagents; ++i)
{
Reagent[i] = _reagents.Reagent[i];
ReagentCount[i] = _reagents.ReagentCount[i];
}
}
ReagentsCurrency = data.ReagentsCurrency;
// SpellShapeshiftEntry
SpellShapeshiftRecord _shapeshift = data.Shapeshift;
if (_shapeshift != null)
{
Stances = MathFunctions.MakePair64(_shapeshift.ShapeshiftMask[0], _shapeshift.ShapeshiftMask[1]);
StancesNot = MathFunctions.MakePair64(_shapeshift.ShapeshiftExclude[0], _shapeshift.ShapeshiftExclude[1]);
}
// SpellTargetRestrictionsEntry
SpellTargetRestrictionsRecord _target = data.TargetRestrictions;
if (_target != null)
{
Targets = (SpellCastTargetFlags)_target.Targets;
ConeAngle = _target.ConeDegrees;
Width = _target.Width;
TargetCreatureType = _target.TargetCreatureType;
MaxAffectedTargets = _target.MaxTargets;
MaxTargetLevel = _target.MaxTargetLevel;
}
// SpellTotemsEntry
SpellTotemsRecord _totem = data.Totems;
if (_totem != null)
{
for (var i = 0; i < 2; ++i)
{
TotemCategory[i] = _totem.RequiredTotemCategoryID[i];
Totem[i] = _totem.Totem[i];
}
}
_visuals = data.Visuals;
_spellSpecific = SpellSpecificType.Normal;
_auraState = AuraStateType.None;
}
public SpellInfo(SpellNameRecord spellName, Difficulty difficulty, List<SpellEffectRecord> effects)
{
Id = spellName.Id;
Difficulty = difficulty;
SpellName = spellName.Name;
foreach (SpellEffectRecord spellEffect in effects)
{
_effects.EnsureWritableListIndex((uint)spellEffect.EffectIndex, new SpellEffectInfo(this));
_effects[(int)spellEffect.EffectIndex] = new SpellEffectInfo(this, spellEffect);
}
// Correct EffectIndex for blank effects
for (int i = 0; i < _effects.Count; ++i)
_effects[i].EffectIndex = (uint)i;
}
public bool HasEffect(SpellEffectName effect)
{
foreach (var effectInfo in _effects)
if (effectInfo.IsEffect(effect))
return true;
return false;
}
public bool HasAura(AuraType aura)
{
foreach (var effectInfo in _effects)
if (effectInfo.IsAura(aura))
return true;
return false;
}
public bool HasAreaAuraEffect()
{
foreach (var effectInfo in _effects)
if (effectInfo.IsAreaAuraEffect())
return true;
return false;
}
public bool HasOnlyDamageEffects()
{
foreach (var effectInfo in _effects)
{
switch (effectInfo.Effect)
{
case SpellEffectName.WeaponDamage:
case SpellEffectName.WeaponDamageNoSchool:
case SpellEffectName.NormalizedWeaponDmg:
case SpellEffectName.WeaponPercentDamage:
case SpellEffectName.SchoolDamage:
case SpellEffectName.EnvironmentalDamage:
case SpellEffectName.HealthLeech:
case SpellEffectName.DamageFromMaxHealthPCT:
continue;
default:
return false;
}
}
return true;
}
public bool IsExplicitDiscovery()
{
if (GetEffects().Count < 2)
return false;
return ((GetEffect(0).Effect == SpellEffectName.CreateRandomItem
|| GetEffect(0).Effect == SpellEffectName.CreateLoot)
&& GetEffect(1).Effect == SpellEffectName.ScriptEffect)
|| Id == 64323;
}
public bool IsLootCrafting()
{
return HasEffect(SpellEffectName.CreateRandomItem) || HasEffect(SpellEffectName.CreateLoot);
}
public bool IsProfession()
{
foreach (var effectInfo in _effects)
{
if (effectInfo.IsEffect(SpellEffectName.Skill))
{
uint skill = (uint)effectInfo.MiscValue;
if (Global.SpellMgr.IsProfessionSkill(skill))
return true;
}
}
return false;
}
public bool IsPrimaryProfession()
{
foreach (var effectInfo in _effects)
if (effectInfo.IsEffect(SpellEffectName.Skill) && Global.SpellMgr.IsPrimaryProfessionSkill((uint)effectInfo.MiscValue))
return true;
return false;
}
public bool IsPrimaryProfessionFirstRank()
{
return IsPrimaryProfession() && GetRank() == 1;
}
public bool IsAbilityOfSkillType(SkillType skillType)
{
var bounds = Global.SpellMgr.GetSkillLineAbilityMapBounds(Id);
foreach (var spell_idx in bounds)
if (spell_idx.SkillLine == (uint)skillType)
return true;
return false;
}
public bool IsAffectingArea()
{
foreach (var effectInfo in _effects)
if (effectInfo.IsEffect() && (effectInfo.IsTargetingArea() || effectInfo.IsEffect(SpellEffectName.PersistentAreaAura) || effectInfo.IsAreaAuraEffect()))
return true;
return false;
}
// checks if spell targets are selected from area, doesn't include spell effects in check (like area wide auras for example)
public bool IsTargetingArea()
{
foreach (var effectInfo in _effects)
if (effectInfo.IsEffect() && effectInfo.IsTargetingArea())
return true;
return false;
}
public bool NeedsExplicitUnitTarget()
{
return Convert.ToBoolean(GetExplicitTargetMask() & SpellCastTargetFlags.UnitMask);
}
public bool NeedsToBeTriggeredByCaster(SpellInfo triggeringSpell)
{
if (NeedsExplicitUnitTarget())
return true;
if (triggeringSpell.IsChanneled())
{
SpellCastTargetFlags mask = 0;
foreach (var effectInfo in _effects)
{
if (effectInfo.TargetA.GetTarget() != Framework.Constants.Targets.UnitCaster && effectInfo.TargetA.GetTarget() != Framework.Constants.Targets.DestCaster
&& effectInfo.TargetB.GetTarget() != Framework.Constants.Targets.UnitCaster && effectInfo.TargetB.GetTarget() != Framework.Constants.Targets.DestCaster)
{
mask |= effectInfo.GetProvidedTargetMask();
}
}
if (mask.HasAnyFlag(SpellCastTargetFlags.UnitMask))
return true;
}
return false;
}
public bool IsPassive()
{
return HasAttribute(SpellAttr0.Passive);
}
public bool IsAutocastable()
{
if (IsPassive())
return false;
if (HasAttribute(SpellAttr1.NoAutocastAi))
return false;
return true;
}
public bool IsStackableWithRanks()
{
if (IsPassive())
return false;
// All stance spells. if any better way, change it.
foreach (var effectInfo in _effects)
{
switch (SpellFamilyName)
{
case SpellFamilyNames.Paladin:
// Paladin aura Spell
if (effectInfo.Effect == SpellEffectName.ApplyAreaAuraRaid)
return false;
break;
case SpellFamilyNames.Druid:
// Druid form Spell
if (effectInfo.Effect == SpellEffectName.ApplyAura &&
effectInfo.ApplyAuraName == AuraType.ModShapeshift)
return false;
break;
}
}
return true;
}
public bool IsPassiveStackableWithRanks()
{
return IsPassive() && !HasEffect(SpellEffectName.ApplyAura);
}
public bool IsMultiSlotAura()
{
return IsPassive() || Id == 55849 || Id == 40075 || Id == 44413; // Power Spark, Fel Flak Fire, Incanter's Absorption
}
public bool IsStackableOnOneSlotWithDifferentCasters()
{
// TODO: Re-verify meaning of SPELL_ATTR3_STACK_FOR_DIFF_CASTERS and update conditions here
return StackAmount > 1 && !IsChanneled() && !HasAttribute(SpellAttr3.DotStackingRule);
}
public bool IsCooldownStartedOnEvent()
{
if (HasAttribute(SpellAttr0.CooldownOnEvent))
return true;
SpellCategoryRecord category = CliDB.SpellCategoryStorage.LookupByKey(CategoryId);
return category != null && category.HasFlag(SpellCategoryFlags.CooldownStartsOnEvent);
}
public bool IsDeathPersistent()
{
return HasAttribute(SpellAttr3.AllowAuraWhileDead);
}
public bool IsRequiringDeadTarget()
{
return HasAttribute(SpellAttr3.OnlyOnGhosts);
}
public bool IsAllowingDeadTarget()
{
if (HasAttribute(SpellAttr2.AllowDeadTarget) || Targets.HasAnyFlag(SpellCastTargetFlags.CorpseAlly | SpellCastTargetFlags.CorpseEnemy | SpellCastTargetFlags.UnitDead))
return true;
foreach (var effectInfo in _effects)
if (effectInfo.TargetA.GetObjectType() == SpellTargetObjectTypes.Corpse || effectInfo.TargetB.GetObjectType() == SpellTargetObjectTypes.Corpse)
return true;
return false;
}
public bool IsGroupBuff()
{
foreach (var effectInfo in _effects)
{
switch (effectInfo.TargetA.GetCheckType())
{
case SpellTargetCheckTypes.Party:
case SpellTargetCheckTypes.Raid:
case SpellTargetCheckTypes.RaidClass:
return true;
default:
break;
}
}
return false;
}
public bool CanBeUsedInCombat(Unit caster)
{
return !HasAttribute(SpellAttr0.NotInCombatOnlyPeaceful)
|| (caster.HasAuraType(AuraType.AllowMountInCombat) && HasAura(AuraType.Mounted));
}
public bool IsPositive()
{
for (var index = 0; index < NegativeEffects.Length; ++index)
if (NegativeEffects.Get(index))
return false;
return true;
}
public bool IsPositiveEffect(uint effIndex)
{
return !NegativeEffects.Get((int)effIndex);
}
public bool IsChanneled()
{
return HasAttribute(SpellAttr1.IsChannelled | SpellAttr1.IsSelfChannelled);
}
public bool IsMoveAllowedChannel()
{
return IsChanneled() && !ChannelInterruptFlags.HasFlag(SpellAuraInterruptFlags.Moving | SpellAuraInterruptFlags.Turning);
}
public bool IsNextMeleeSwingSpell()
{
return HasAttribute(SpellAttr0.OnNextSwingNoDamage | SpellAttr0.OnNextSwing);
}
public bool IsRangedWeaponSpell()
{
return (SpellFamilyName == SpellFamilyNames.Hunter && !SpellFamilyFlags[1].HasAnyFlag(0x10000000u)) // for 53352, cannot find better way
|| Convert.ToBoolean(EquippedItemSubClassMask & (int)ItemSubClassWeapon.MaskRanged)
|| Attributes.HasAnyFlag(SpellAttr0.UsesRangedSlot);
}
public bool IsAutoRepeatRangedSpell()
{
return HasAttribute(SpellAttr2.AutoRepeat);
}
public bool IsEmpowerSpell()
{
return !EmpowerStageThresholds.Empty();
}
public bool HasInitialAggro()
{
return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr2.NoInitialThreat) || HasAttribute(SpellAttr4.NoHarmfulThreat));
}
public bool HasHitDelay()
{
return Speed > 0.0f || LaunchDelay > 0.0f;
}
public WeaponAttackType GetAttackType()
{
WeaponAttackType result;
switch (DmgClass)
{
case SpellDmgClass.Melee:
if (HasAttribute(SpellAttr3.RequiresOffHandWeapon))
result = WeaponAttackType.OffAttack;
else
result = WeaponAttackType.BaseAttack;
break;
case SpellDmgClass.Ranged:
result = IsRangedWeaponSpell() ? WeaponAttackType.RangedAttack : WeaponAttackType.BaseAttack;
break;
default:
// Wands
if (IsAutoRepeatRangedSpell())
result = WeaponAttackType.RangedAttack;
else
result = WeaponAttackType.BaseAttack;
break;
}
return result;
}
public bool IsItemFitToSpellRequirements(Item item)
{
// item neutral spell
if (EquippedItemClass == ItemClass.None)
return true;
// item dependent spell
if (item != null && item.IsFitToSpellRequirements(this))
return true;
return false;
}
public bool IsAffected(SpellFamilyNames familyName, FlagArray128 familyFlags)
{
if (familyName == 0)
return true;
if (familyName != SpellFamilyName)
return false;
if (familyFlags && !(familyFlags & SpellFamilyFlags))
return false;
return true;
}
bool IsAffectedBySpellMods()
{
return !HasAttribute(SpellAttr3.IgnoreCasterModifiers);
}
public bool IsAffectedBySpellMod(SpellModifier mod)
{
if (!IsAffectedBySpellMods())
return false;
SpellInfo affectSpell = Global.SpellMgr.GetSpellInfo(mod.spellId, Difficulty);
if (affectSpell == null)
return false;
switch (mod.type)
{
case SpellModType.Flat:
case SpellModType.Pct:
// TEMP: dont use IsAffected - !familyName and !familyFlags are not valid options for spell mods
// TODO: investigate if the !familyName and !familyFlags conditions are even valid for all other (nonmod) uses of SpellInfo::IsAffected
return affectSpell.SpellFamilyName == SpellFamilyName && (mod as SpellModifierByClassMask).mask & SpellFamilyFlags;
case SpellModType.LabelFlat:
return HasLabel((uint)(mod as SpellFlatModifierByLabel).value.LabelID);
case SpellModType.LabelPct:
return HasLabel((uint)(mod as SpellPctModifierByLabel).value.LabelID);
default:
break;
}
return false;
}
public bool CanPierceImmuneAura(SpellInfo auraSpellInfo)
{
// aura can't be pierced
if (auraSpellInfo == null || auraSpellInfo.HasAttribute(SpellAttr0.NoImmunities))
return false;
// these spells pierce all avalible spells (Resurrection Sickness for example)
if (HasAttribute(SpellAttr0.NoImmunities))
return true;
// these spells (Cyclone for example) can pierce all...
if (HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || HasAttribute(SpellAttr2.NoSchoolImmunities))
{
// ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
if (auraSpellInfo.Mechanic != Mechanics.ImmuneShield &&
auraSpellInfo.Mechanic != Mechanics.Invulnerability &&
(auraSpellInfo.Mechanic != Mechanics.Banish || (IsRankOf(auraSpellInfo) && auraSpellInfo.Dispel != DispelType.None))) // Banish shouldn't be immune to itself, but Cyclone should
return true;
}
// Dispels other auras on immunity, check if this spell makes the unit immune to aura
if (HasAttribute(SpellAttr1.ImmunityPurgesEffect) && CanSpellProvideImmunityAgainstAura(auraSpellInfo))
return true;
return false;
}
public bool CanDispelAura(SpellInfo auraSpellInfo)
{
// These auras (like Divine Shield) can't be dispelled
if (auraSpellInfo.HasAttribute(SpellAttr0.NoImmunities))
return false;
// These spells (like Mass Dispel) can dispel all auras
if (HasAttribute(SpellAttr0.NoImmunities))
return true;
// These auras (Cyclone for example) are not dispelable
if ((auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && auraSpellInfo.Mechanic != Mechanics.None)
|| auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
return false;
return true;
}
public bool IsSingleTarget()
{
// all other single target spells have if it has AttributesEx5
if (HasAttribute(SpellAttr5.LimitN))
return true;
return false;
}
public bool IsAuraExclusiveBySpecificWith(SpellInfo spellInfo)
{
SpellSpecificType spellSpec1 = GetSpellSpecific();
SpellSpecificType spellSpec2 = spellInfo.GetSpellSpecific();
switch (spellSpec1)
{
case SpellSpecificType.WarlockArmor:
case SpellSpecificType.MageArmor:
case SpellSpecificType.ElementalShield:
case SpellSpecificType.MagePolymorph:
case SpellSpecificType.Presence:
case SpellSpecificType.Charm:
case SpellSpecificType.Scroll:
case SpellSpecificType.WarriorEnrage:
case SpellSpecificType.MageArcaneBrillance:
case SpellSpecificType.PriestDivineSpirit:
return spellSpec1 == spellSpec2;
case SpellSpecificType.Food:
return spellSpec2 == SpellSpecificType.Food
|| spellSpec2 == SpellSpecificType.FoodAndDrink;
case SpellSpecificType.Drink:
return spellSpec2 == SpellSpecificType.Drink
|| spellSpec2 == SpellSpecificType.FoodAndDrink;
case SpellSpecificType.FoodAndDrink:
return spellSpec2 == SpellSpecificType.Food
|| spellSpec2 == SpellSpecificType.Drink
|| spellSpec2 == SpellSpecificType.FoodAndDrink;
default:
return false;
}
}
public bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo spellInfo)
{
SpellSpecificType spellSpec = GetSpellSpecific();
switch (spellSpec)
{
case SpellSpecificType.Seal:
case SpellSpecificType.Hand:
case SpellSpecificType.Aura:
case SpellSpecificType.Sting:
case SpellSpecificType.Curse:
case SpellSpecificType.Bane:
case SpellSpecificType.Aspect:
case SpellSpecificType.WarlockCorruption:
return spellSpec == spellInfo.GetSpellSpecific();
default:
return false;
}
}
public SpellCastResult CheckShapeshift(ShapeShiftForm form)
{
// talents that learn spells can have stance requirements that need ignore
// (this requirement only for client-side stance show in talent description)
/* TODO: 6.x fix this in proper way (probably spell flags/attributes?)
if (CliDB.GetTalentSpellCost(Id) > 0 && HasEffect(SpellEffects.LearnSpell))
return SpellCastResult.SpellCastOk;
*/
//if (HasAttribute(SPELL_ATTR13_ACTIVATES_REQUIRED_SHAPESHIFT))
// return SPELL_CAST_OK;
ulong stanceMask = (form != 0 ? 1ul << ((int)form - 1) : 0);
if (Convert.ToBoolean(stanceMask & StancesNot)) // can explicitly not be casted in this stance
return SpellCastResult.NotShapeshift;
if (Convert.ToBoolean(stanceMask & Stances)) // can explicitly be casted in this stance
return SpellCastResult.SpellCastOk;
bool actAsShifted = false;
SpellShapeshiftFormRecord shapeInfo = null;
if (form > 0)
{
shapeInfo = CliDB.SpellShapeshiftFormStorage.LookupByKey(form);
if (shapeInfo == null)
{
Log.outError(LogFilter.Spells, "GetErrorAtShapeshiftedCast: unknown shapeshift {0}", form);
return SpellCastResult.SpellCastOk;
}
actAsShifted = !shapeInfo.HasFlag(SpellShapeshiftFormFlags.Stance);
}
if (actAsShifted)
{
if (HasAttribute(SpellAttr0.NotShapeshifted) || (shapeInfo != null && shapeInfo.HasFlag(SpellShapeshiftFormFlags.CanOnlyCastShapeshiftSpells))) // not while shapeshifted
return SpellCastResult.NotShapeshift;
else if (Stances != 0) // needs other shapeshift
return SpellCastResult.OnlyShapeshift;
}
else
{
// needs shapeshift
if (!HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm) && Stances != 0)
return SpellCastResult.OnlyShapeshift;
}
return SpellCastResult.SpellCastOk;
}
public SpellCastResult CheckLocation(uint map_id, uint zone_id, uint area_id, Player player)
{
// normal case
if (RequiredAreasID > 0)
{
bool found = false;
List<uint> areaGroupMembers = Global.DB2Mgr.GetAreasForGroup((uint)RequiredAreasID);
foreach (uint areaId in areaGroupMembers)
{
if (Global.DB2Mgr.IsInArea(area_id, areaId))
{
found = true;
break;
}
}
if (!found)
return SpellCastResult.IncorrectArea;
}
// continent limitation (virtual continent)
if (HasAttribute(SpellAttr4.OnlyFlyingAreas))
{
AreaMountFlags mountFlags = 0;
if (player != null && player.HasAuraType(AuraType.MountRestrictions))
{
foreach (AuraEffect auraEffect in player.GetAuraEffectsByType(AuraType.MountRestrictions))
mountFlags |= (AreaMountFlags)auraEffect.GetMiscValue();
}
else
{
AreaTableRecord areaTable = CliDB.AreaTableStorage.LookupByKey(area_id);
if (areaTable != null)
mountFlags = (AreaMountFlags)areaTable.MountFlags;
}
if (!mountFlags.HasFlag(AreaMountFlags.AllowFlyingMounts))
return SpellCastResult.IncorrectArea;
if (player != null && !ConditionManager.IsPlayerMeetingCondition(player, 72968)) // Hardcoded PlayerCondition id for attribute check in client
return SpellCastResult.IncorrectArea;
}
var mapEntry = CliDB.MapStorage.LookupByKey(map_id);
// raid instance limitation
if (HasAttribute(SpellAttr6.NotInRaidInstances))
{
if (mapEntry == null || mapEntry.IsRaid())
return SpellCastResult.NotInRaidInstance;
}
if (HasAttribute(SpellAttr8.RemoveOutsideDungeonsAndRaids))
{
if (mapEntry == null || !mapEntry.IsDungeon())
return SpellCastResult.TargetNotInInstance;
}
if (HasAttribute(SpellAttr8.NotInBattleground))
{
if (mapEntry == null || mapEntry.IsBattleground())
return SpellCastResult.NotInBattleground;
}
// DB base check (if non empty then must fit at least single for allow)
var saBounds = Global.SpellMgr.GetSpellAreaMapBounds(Id);
if (!saBounds.Empty())
{
foreach (var bound in saBounds)
{
if (bound.IsFitToRequirements(player, zone_id, area_id))
return SpellCastResult.SpellCastOk;
}
return SpellCastResult.IncorrectArea;
}
// bg spell checks
switch (Id)
{
case 23333: // Warsong Flag
case 23335: // Silverwing Flag
return map_id == 489 && player != null && player.InBattleground() ? SpellCastResult.SpellCastOk : SpellCastResult.RequiresArea;
case 2584: // Waiting to Resurrect
case 42792: // Recently Dropped Flag
case 43681: // Inactive
case 44535: // Spirit Heal (mana)
if (mapEntry == null)
return SpellCastResult.IncorrectArea;
return zone_id == (uint)AreaId.Wintergrasp || (mapEntry.IsBattleground() && player != null && player.InBattleground()) ? SpellCastResult.SpellCastOk : SpellCastResult.RequiresArea;
case 44521: // Preparation
{
if (player == null)
return SpellCastResult.RequiresArea;
if (mapEntry == null)
return SpellCastResult.IncorrectArea;
if (!mapEntry.IsBattleground())
return SpellCastResult.RequiresArea;
Battleground bg = player.GetBattleground();
return bg != null && bg.GetStatus() == BattlegroundStatus.WaitJoin ? SpellCastResult.SpellCastOk : SpellCastResult.RequiresArea;
}
case 32724: // Gold Team (Alliance)
case 32725: // Green Team (Alliance)
case 35774: // Gold Team (Horde)
case 35775: // Green Team (Horde)
if (mapEntry == null)
return SpellCastResult.IncorrectArea;
return mapEntry.IsBattleArena() && player != null && player.InBattleground() ? SpellCastResult.SpellCastOk : SpellCastResult.RequiresArea;
case 32727: // Arena Preparation
{
if (player == null)
return SpellCastResult.RequiresArea;
if (mapEntry == null)
return SpellCastResult.IncorrectArea;
if (!mapEntry.IsBattleArena())
return SpellCastResult.RequiresArea;
Battleground bg = player.GetBattleground();
return bg != null && bg.GetStatus() == BattlegroundStatus.WaitJoin ? SpellCastResult.SpellCastOk : SpellCastResult.RequiresArea;
}
}
// aura limitations
if (player != null)
{
foreach (var effectInfo in _effects)
{
if (!effectInfo.IsAura())
continue;
switch (effectInfo.ApplyAuraName)
{
case AuraType.ModShapeshift:
{
SpellShapeshiftFormRecord spellShapeshiftForm = CliDB.SpellShapeshiftFormStorage.LookupByKey(effectInfo.MiscValue);
if (spellShapeshiftForm != null)
{
uint mountType = spellShapeshiftForm.MountTypeID;
if (mountType != 0)
if (player.GetMountCapability(mountType) == null)
return SpellCastResult.NotHere;
}
break;
}
case AuraType.Mounted:
{
uint mountType = (uint)effectInfo.MiscValueB;
MountRecord mountEntry = Global.DB2Mgr.GetMount(Id);
if (mountEntry != null)
mountType = mountEntry.MountTypeID;
if (mountType != 0 && player.GetMountCapability(mountType) == null)
return SpellCastResult.NotHere;
break;
}
}
}
}
return SpellCastResult.SpellCastOk;
}
public SpellCastResult CheckTarget(WorldObject caster, WorldObject target, bool Implicit = true)
{
if (HasAttribute(SpellAttr1.ExcludeCaster) && caster == target)
return SpellCastResult.BadTargets;
// check visibility - ignore invisibility/stealth for implicit (area) targets
if (!HasAttribute(SpellAttr6.IgnorePhaseShift) && !caster.CanSeeOrDetect(target, Implicit))
return SpellCastResult.BadTargets;
Unit unitTarget = target.ToUnit();
if (HasAttribute(SpellAttr8.OnlyTargetIfSameCreator))
{
var getCreatorOrSelf = (WorldObject obj) =>
{
ObjectGuid creator = obj.GetCreatorGUID();
if (creator.IsEmpty())
creator = obj.GetGUID();
return creator;
};
if (getCreatorOrSelf(caster) != getCreatorOrSelf(target))
return SpellCastResult.BadTargets;
}
// creature/player specific target checks
if (unitTarget != null)
{
// spells cannot be cast if target has a pet in combat either
if (HasAttribute(SpellAttr1.OnlyPeacefulTargets) && (unitTarget.IsInCombat() || unitTarget.HasUnitFlag(UnitFlags.PetInCombat)))
return SpellCastResult.TargetAffectingCombat;
// only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts
if (HasAttribute(SpellAttr3.OnlyOnGhosts) != unitTarget.HasAuraType(AuraType.Ghost))
{
if (HasAttribute(SpellAttr3.OnlyOnGhosts))
return SpellCastResult.TargetNotGhost;
else
return SpellCastResult.BadTargets;
}
if (caster != unitTarget)
{
if (caster.IsTypeId(TypeId.Player))
{
// Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
if (HasAttribute(SpellAttr2.CannotCastOnTapped))
{
Creature targetCreature = unitTarget.ToCreature();
if (targetCreature != null)
if (targetCreature.HasLootRecipient() && !targetCreature.IsTappedBy(caster.ToPlayer()))
return SpellCastResult.CantCastOnTapped;
}
if (HasAttribute(SpellCustomAttributes.PickPocket))
{
Creature targetCreature = unitTarget.ToCreature();
if (targetCreature == null)
return SpellCastResult.BadTargets;
if (!targetCreature.CanHaveLoot() || !Loots.LootStorage.Pickpocketing.HaveLootFor(targetCreature.GetCreatureDifficulty().PickPocketLootID))
return SpellCastResult.TargetNoPockets;
}
// Not allow disarm unarmed player
if (Mechanic == Mechanics.Disarm)
{
if (unitTarget.IsTypeId(TypeId.Player))
{
Player player = unitTarget.ToPlayer();
if (player.GetWeaponForAttack(WeaponAttackType.BaseAttack) == null || !player.IsUseEquipedWeapon(true))
return SpellCastResult.TargetNoWeapons;
}
else if (unitTarget.GetVirtualItemId(0) == 0)
return SpellCastResult.TargetNoWeapons;
}
}
}
if (HasAttribute(SpellAttr8.OnlyTargetOwnSummons))
if (!unitTarget.IsSummon() || unitTarget.ToTempSummon().GetSummonerGUID() != caster.GetGUID())
return SpellCastResult.BadTargets;
if (HasAttribute(SpellAttr3.NotOnAoeImmune))
if (unitTarget.GetSpellOtherImmunityMask().HasFlag(SpellOtherImmunity.AoETarget))
return SpellCastResult.BadTargets;
if (HasAttribute(SpellAttr9.TargetMustBeGrounded) &&
(unitTarget.HasUnitMovementFlag(MovementFlag.Falling | MovementFlag.Swimming | MovementFlag.Flying | MovementFlag.Hover) ||
unitTarget.HasExtraUnitMovementFlag2(MovementFlags3.AdvFlying)))
return SpellCastResult.TargetNotGrounded;
}
// corpse specific target checks
else if (target.IsTypeId(TypeId.Corpse))
{
Corpse corpseTarget = target.ToCorpse();
// cannot target bare bones
if (corpseTarget.GetCorpseType() == CorpseType.Bones)
return SpellCastResult.BadTargets;
// we have to use owner for some checks (aura preventing resurrection for example)
Player owner = Global.ObjAccessor.FindPlayer(corpseTarget.GetOwnerGUID());
if (owner != null)
unitTarget = owner;
// we're not interested in corpses without owner
else
return SpellCastResult.BadTargets;
}
// other types of objects - always valid
else
return SpellCastResult.SpellCastOk;
// corpseOwner and unit specific target checks
if (!unitTarget.IsPlayer())
{
if (HasAttribute(SpellAttr3.OnlyOnPlayer))
return SpellCastResult.TargetNotPlayer;
if (HasAttribute(SpellAttr5.NotOnPlayerControlledNpc) && unitTarget.IsControlledByPlayer())
return SpellCastResult.TargetIsPlayerControlled;
}
else if (HasAttribute(SpellAttr5.NotOnPlayer))
return SpellCastResult.TargetIsPlayer;
if (!IsAllowingDeadTarget() && !unitTarget.IsAlive())
return SpellCastResult.TargetsDead;
// check this flag only for implicit targets (chain and area), allow to explicitly target units for spells like Shield of Righteousness
if (Implicit && HasAttribute(SpellAttr6.DoNotChainToCrowdControlledTargets) && !unitTarget.CanFreeMove())
return SpellCastResult.BadTargets;
if (!CheckTargetCreatureType(unitTarget))
{
if (target.IsTypeId(TypeId.Player))
return SpellCastResult.TargetIsPlayer;
else
return SpellCastResult.BadTargets;
}
// check GM mode and GM invisibility - only for player casts (npc casts are controlled by AI) and negative spells
if (unitTarget != caster && (caster.GetAffectingPlayer() != null || !IsPositive()) && unitTarget.IsTypeId(TypeId.Player))
{
if (!unitTarget.ToPlayer().IsVisible())
return SpellCastResult.BmOrInvisgod;
if (unitTarget.ToPlayer().IsGameMaster())
return SpellCastResult.BmOrInvisgod;
}
// not allow casting on flying player
if (unitTarget.HasUnitState(UnitState.InFlight) && !HasAttribute(SpellCustomAttributes.AllowInflightTarget))
return SpellCastResult.BadTargets;
/* TARGET_UNIT_MASTER gets blocked here for passengers, because the whole idea of this check is to
not allow passengers to be implicitly hit by spells, however this target type should be an exception,
if this is left it kills spells that award kill credit from vehicle to master (few spells),
the use of these 2 covers passenger target check, logically, if vehicle cast this to master it should always hit
him, because it would be it's passenger, there's no such case where this gets to fail legitimacy, this problem
cannot be solved from within the check in other way since target type cannot be called for the spell currently
Spell examples: [ID - 52864 Devour Water, ID - 52862 Devour Wind, ID - 49370 Wyrmrest Defender: Destabilize Azure Dragonshrine Effect] */
Unit unitCaster = caster.ToUnit();
if (unitCaster != null)
{
if (!unitCaster.IsVehicle() && unitCaster.GetCharmerOrOwner() != target)
{
if (TargetAuraState != 0 && !unitTarget.HasAuraState(TargetAuraState, this, unitCaster))
return SpellCastResult.TargetAurastate;
if (ExcludeTargetAuraState != 0 && unitTarget.HasAuraState(ExcludeTargetAuraState, this, unitCaster))
return SpellCastResult.TargetAurastate;
}
}
if (TargetAuraSpell != 0 && !unitTarget.HasAura(TargetAuraSpell))
return SpellCastResult.TargetAurastate;
if (ExcludeTargetAuraSpell != 0 && unitTarget.HasAura(ExcludeTargetAuraSpell))
return SpellCastResult.TargetAurastate;
if (unitTarget.HasAuraType(AuraType.PreventResurrection) && !HasAttribute(SpellAttr7.BypassNoResurrectAura))
if (HasEffect(SpellEffectName.SelfResurrect) || HasEffect(SpellEffectName.Resurrect))
return SpellCastResult.TargetCannotBeResurrected;
if (HasAttribute(SpellAttr8.EnforceInCombatRessurectionLimit))
{
Map map = caster.GetMap();
if (map != null)
{
InstanceMap iMap = map.ToInstanceMap();
if (iMap != null)
{
InstanceScript instance = iMap.GetInstanceScript();
if (instance != null)
if (instance.GetCombatResurrectionCharges() == 0 && instance.IsEncounterInProgress())
return SpellCastResult.TargetCannotBeResurrected;
}
}
}
return SpellCastResult.SpellCastOk;
}
public SpellCastResult CheckExplicitTarget(WorldObject caster, WorldObject target, Item itemTarget = null)
{
SpellCastTargetFlags neededTargets = GetExplicitTargetMask();
if (target == null)
{
if (Convert.ToBoolean(neededTargets & (SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.GameobjectMask | SpellCastTargetFlags.CorpseMask)))
if (!Convert.ToBoolean(neededTargets & SpellCastTargetFlags.GameobjectItem) || itemTarget == null)
return SpellCastResult.BadTargets;
return SpellCastResult.SpellCastOk;
}
Unit unitTarget = target.ToUnit();
if (unitTarget != null)
{
if (neededTargets.HasAnyFlag(SpellCastTargetFlags.UnitEnemy | SpellCastTargetFlags.UnitAlly | SpellCastTargetFlags.UnitRaid | SpellCastTargetFlags.UnitParty | SpellCastTargetFlags.UnitMinipet | SpellCastTargetFlags.UnitPassenger))
{
Unit unitCaster = caster.ToUnit();
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitEnemy))
if (caster.IsValidAttackTarget(unitTarget, this))
return SpellCastResult.SpellCastOk;
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitAlly)
|| (neededTargets.HasFlag(SpellCastTargetFlags.UnitParty) && unitCaster != null && unitCaster.IsInPartyWith(unitTarget))
|| (neededTargets.HasFlag(SpellCastTargetFlags.UnitRaid) && unitCaster != null && unitCaster.IsInRaidWith(unitTarget)))
if (caster.IsValidAssistTarget(unitTarget, this))
return SpellCastResult.SpellCastOk;
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitMinipet) && unitCaster != null)
if (unitTarget.GetGUID() == unitCaster.GetCritterGUID())
return SpellCastResult.SpellCastOk;
if (neededTargets.HasFlag(SpellCastTargetFlags.UnitPassenger) && unitCaster != null)
if (unitTarget.IsOnVehicle(unitCaster))
return SpellCastResult.SpellCastOk;
return SpellCastResult.BadTargets;
}
}
return SpellCastResult.SpellCastOk;
}
public SpellCastResult CheckVehicle(Unit caster)
{
// All creatures should be able to cast as passengers freely, restriction and attribute are only for players
if (!caster.IsTypeId(TypeId.Player))
return SpellCastResult.SpellCastOk;
Vehicle vehicle = caster.GetVehicle();
if (vehicle != null)
{
VehicleSeatFlags checkMask = 0;
foreach (var effectInfo in _effects)
{
if (effectInfo.IsAura(AuraType.ModShapeshift))
{
var shapeShiftFromEntry = CliDB.SpellShapeshiftFormStorage.LookupByKey((uint)effectInfo.MiscValue);
if (shapeShiftFromEntry != null && !shapeShiftFromEntry.HasFlag(SpellShapeshiftFormFlags.Stance))
checkMask |= VehicleSeatFlags.Uncontrolled;
break;
}
}
if (HasAura(AuraType.Mounted))
checkMask |= VehicleSeatFlags.CanCastMountSpell;
if (checkMask == 0)
checkMask = VehicleSeatFlags.CanAttack;
var vehicleSeat = vehicle.GetSeatForPassenger(caster);
if (!HasAttribute(SpellAttr6.AllowWhileRidingVehicle) && !HasAttribute(SpellAttr0.AllowWhileMounted)
&& (vehicleSeat.Flags & (int)checkMask) != (int)checkMask)
return SpellCastResult.CantDoThatRightNow;
// Can only summon uncontrolled minions/guardians when on controlled vehicle
if (vehicleSeat.HasFlag(VehicleSeatFlags.CanControl | VehicleSeatFlags.Unk2))
{
foreach (var effectInfo in _effects)
{
if (!effectInfo.IsEffect(SpellEffectName.Summon))
continue;
var props = CliDB.SummonPropertiesStorage.LookupByKey(effectInfo.MiscValueB);
if (props != null && props.Control != SummonCategory.Wild)
return SpellCastResult.CantDoThatRightNow;
}
}
}
return SpellCastResult.SpellCastOk;
}
public bool CheckTargetCreatureType(Unit target)
{
// Curse of Doom & Exorcism: not find another way to fix spell target check :/
if (SpellFamilyName == SpellFamilyNames.Warlock && GetCategory() == 1179)
{
// not allow cast at player
if (target.IsTypeId(TypeId.Player))
return false;
else
return true;
}
// if target is magnet (i.e Grounding Totem) the check is skipped
if (target.IsMagnet())
return true;
uint creatureType = target.GetCreatureTypeMask();
return TargetCreatureType == 0 || creatureType == 0 || (creatureType & TargetCreatureType) != 0 || target.HasAuraType(AuraType.IgnoreSpellCreatureTypeRequirements);
}
public SpellSchoolMask GetSchoolMask()
{
return SchoolMask;
}
public ulong GetAllEffectsMechanicMask()
{
ulong mask = 0;
if (Mechanic != 0)
mask |= 1ul << (int)Mechanic;
foreach (var effectInfo in _effects)
if (effectInfo.IsEffect() && effectInfo.Mechanic != 0)
mask |= 1ul << (int)effectInfo.Mechanic;
return mask;
}
public ulong GetEffectMechanicMask(uint effIndex)
{
ulong mask = 0;
if (Mechanic != 0)
mask |= 1ul << (int)Mechanic;
if (GetEffect(effIndex).IsEffect() && GetEffect(effIndex).Mechanic != 0)
mask |= 1ul << (int)GetEffect(effIndex).Mechanic;
return mask;
}
public ulong GetSpellMechanicMaskByEffectMask(uint effectMask)
{
ulong mask = 0;
if (Mechanic != 0)
mask |= 1ul << (int)Mechanic;
foreach (var effectInfo in _effects)
if ((effectMask & (1 << (int)effectInfo.EffectIndex)) != 0 && effectInfo.Mechanic != 0)
mask |= 1ul << (int)effectInfo.Mechanic;
return mask;
}
public Mechanics GetEffectMechanic(uint effIndex)
{
if (GetEffect(effIndex).IsEffect() && GetEffect(effIndex).Mechanic != 0)
return GetEffect(effIndex).Mechanic;
if (Mechanic != 0)
return Mechanic;
return Mechanics.None;
}
public uint GetDispelMask()
{
return GetDispelMask(Dispel);
}
public static uint GetDispelMask(DispelType type)
{
// If dispel all
if (type == DispelType.ALL)
return (uint)DispelType.AllMask;
else
return (uint)(1 << (int)type);
}
public SpellCastTargetFlags GetExplicitTargetMask()
{
return (SpellCastTargetFlags)ExplicitTargetMask;
}
public AuraStateType GetAuraState()
{
return _auraState;
}
public void _LoadAuraState()
{
_auraState = AuraStateType.None;
// Faerie Fire
if (GetCategory() == 1133)
_auraState = AuraStateType.FaerieFire;
// Swiftmend state on Regrowth, Rejuvenation, Wild Growth
if (SpellFamilyName == SpellFamilyNames.Druid && (SpellFamilyFlags[0].HasAnyFlag(0x50u) || SpellFamilyFlags[1].HasAnyFlag(0x4000000u)))
_auraState = AuraStateType.DruidPeriodicHeal;
// Deadly poison aura state
if (SpellFamilyName == SpellFamilyNames.Rogue && SpellFamilyFlags[0].HasAnyFlag(0x10000u))
_auraState = AuraStateType.RoguePoisoned;
// Enrage aura state
if (Dispel == DispelType.Enrage)
_auraState = AuraStateType.Enraged;
// Bleeding aura state
if (Convert.ToBoolean(GetAllEffectsMechanicMask() & (1 << (int)Mechanics.Bleed)))
_auraState = AuraStateType.Bleed;
if (Convert.ToBoolean(GetSchoolMask() & SpellSchoolMask.Frost))
{
foreach (var effectInfo in _effects)
if (effectInfo.IsAura(AuraType.ModStun) || effectInfo.IsAura(AuraType.ModRoot) || effectInfo.IsAura(AuraType.ModRoot2))
_auraState = AuraStateType.Frozen;
}
switch (Id)
{
case 1064: // Dazed
_auraState = AuraStateType.Dazed;
break;
case 32216: // Victorious
_auraState = AuraStateType.Victorious;
break;
case 71465: // Divine Surge
case 50241: // Evasive Charges
case 81262: // Efflorescence
_auraState = AuraStateType.RaidEncounter;
break;
case 6950: // Faerie Fire
case 9806: // Phantom Strike
case 9991: // Touch of Zanzil
case 13424: // Faerie Fire
case 13752: // Faerie Fire
case 16432: // Plague Mist
case 20656: // Faerie Fire
case 25602: // Faerie Fire
case 32129: // Faerie Fire
case 35325: // Glowing Blood
case 35328: // Lambent Blood
case 35329: // Vibrant Blood
case 35331: // Black Blood
case 49163: // Perpetual Instability
case 65863: // Faerie Fire
case 79559: // Luxscale Light
case 82855: // Dazzling
case 102953: // In the Rumpus
case 127907: // Phosphorescence
case 127913: // Phosphorescence
case 129007: // Zijin Sting
case 130159: // Fae Touch
case 142537: // Spotter Smoke
case 168455: // Spotted!
case 176905: // Super Sticky Glitter Bomb
case 189502: // Marked
case 201785: // Intruder Alert!
case 201786: // Intruder Alert!
case 201935: // Spotted!
case 239233: // Smoke Bomb
case 319400: // Glitter Burst
case 321470: // Dimensional Shifter Mishap
case 331134: // Spotted
_auraState = AuraStateType.FaerieFire;
break;
default:
break;
}
if (Mechanic == Mechanics.Banish)
_auraState = AuraStateType.Banished;
}
public SpellSpecificType GetSpellSpecific()
{
return _spellSpecific;
}
public void _LoadSpellSpecific()
{
_spellSpecific = SpellSpecificType.Normal;
switch (SpellFamilyName)
{
case SpellFamilyNames.Generic:
{
// Food / Drinks (mostly)
if (HasAuraInterruptFlag(SpellAuraInterruptFlags.Standing))
{
bool food = false;
bool drink = false;
foreach (var effectInfo in _effects)
{
if (!effectInfo.IsAura())
continue;
switch (effectInfo.ApplyAuraName)
{
// Food
case AuraType.ModRegen:
case AuraType.ObsModHealth:
food = true;
break;
// Drink
case AuraType.ModPowerRegen:
case AuraType.ObsModPower:
drink = true;
break;
default:
break;
}
}
if (food && drink)
_spellSpecific = SpellSpecificType.FoodAndDrink;
else if (food)
_spellSpecific = SpellSpecificType.Food;
else if (drink)
_spellSpecific = SpellSpecificType.Drink;
}
// scrolls effects
else
{
SpellInfo firstRankSpellInfo = GetFirstRankSpell();
switch (firstRankSpellInfo.Id)
{
case 8118: // Strength
case 8099: // Stamina
case 8112: // Spirit
case 8096: // Intellect
case 8115: // Agility
case 8091: // Armor
_spellSpecific = SpellSpecificType.Scroll;
break;
}
}
break;
}
case SpellFamilyNames.Mage:
{
// family flags 18(Molten), 25(Frost/Ice), 28(Mage)
if (SpellFamilyFlags[0].HasAnyFlag(0x12040000u))
_spellSpecific = SpellSpecificType.MageArmor;
// Arcane brillance and Arcane intelect (normal check fails because of flags difference)
if (SpellFamilyFlags[0].HasAnyFlag(0x400u))
_spellSpecific = SpellSpecificType.MageArcaneBrillance;
if (SpellFamilyFlags[0].HasAnyFlag(0x1000000u) && GetEffect(0).IsAura(AuraType.ModConfuse))
_spellSpecific = SpellSpecificType.MagePolymorph;
break;
}
case SpellFamilyNames.Warrior:
{
if (Id == 12292) // Death Wish
_spellSpecific = SpellSpecificType.WarriorEnrage;
break;
}
case SpellFamilyNames.Warlock:
{
// Warlock (Bane of Doom | Bane of Agony | Bane of Havoc)
if (Id == 603 || Id == 980 || Id == 80240)
_spellSpecific = SpellSpecificType.Bane;
// only warlock curses have this
if (Dispel == DispelType.Curse)
_spellSpecific = SpellSpecificType.Curse;
// Warlock (Demon Armor | Demon Skin | Fel Armor)
if (SpellFamilyFlags[1].HasAnyFlag(0x20000020u) || SpellFamilyFlags[2].HasAnyFlag(0x00000010u))
_spellSpecific = SpellSpecificType.WarlockArmor;
//seed of corruption and corruption
if (SpellFamilyFlags[1].HasAnyFlag(0x10u) || SpellFamilyFlags[0].HasAnyFlag(0x2u))
_spellSpecific = SpellSpecificType.WarlockCorruption;
break;
}
case SpellFamilyNames.Priest:
{
// Divine Spirit and Prayer of Spirit
if (SpellFamilyFlags[0].HasAnyFlag(0x20u))
_spellSpecific = SpellSpecificType.PriestDivineSpirit;
break;
}
case SpellFamilyNames.Hunter:
{
// only hunter stings have this
if (Dispel == DispelType.Poison)
_spellSpecific = SpellSpecificType.Sting;
// only hunter aspects have this (but not all aspects in hunter family)
if (SpellFamilyFlags & new FlagArray128(0x00200000, 0x00000000, 0x00001010, 0x00000000))
_spellSpecific = SpellSpecificType.Aspect;
break;
}
case SpellFamilyNames.Paladin:
{
// Collection of all the seal family flags. No other paladin spell has any of those.
if (SpellFamilyFlags[1].HasAnyFlag(0xA2000800))
_spellSpecific = SpellSpecificType.Seal;
if (SpellFamilyFlags[0].HasAnyFlag(0x00002190u))
_spellSpecific = SpellSpecificType.Hand;
// only paladin auras have this (for palaldin class family)
switch (Id)
{
case 465: // Devotion Aura
case 32223: // Crusader Aura
case 183435: // Retribution Aura
case 317920: // Concentration Aura
_spellSpecific = SpellSpecificType.Aura;
break;
default:
break;
}
break;
}
case SpellFamilyNames.Shaman:
{
// family flags 10 (Lightning), 42 (Earth), 37 (Water), proc shield from T2 8 pieces bonus
if (SpellFamilyFlags[1].HasAnyFlag(0x420u) || SpellFamilyFlags[0].HasAnyFlag(0x00000400u) || Id == 23552)
_spellSpecific = SpellSpecificType.ElementalShield;
break;
}
case SpellFamilyNames.Deathknight:
if (Id == 48266 || Id == 48263 || Id == 48265)
_spellSpecific = SpellSpecificType.Presence;
break;
}
foreach (var effectInfo in _effects)
{
if (effectInfo.IsEffect(SpellEffectName.ApplyAura))
{
switch (effectInfo.ApplyAuraName)
{
case AuraType.ModCharm:
case AuraType.ModPossessPet:
case AuraType.ModPossess:
case AuraType.AoeCharm:
_spellSpecific = SpellSpecificType.Charm;
break;
case AuraType.TrackCreatures:
// @workaround For non-stacking tracking spells (We need generic solution)
if (Id == 30645) // Gas Cloud Tracking
_spellSpecific = SpellSpecificType.Normal;
break;
case AuraType.TrackResources:
case AuraType.TrackStealthed:
_spellSpecific = SpellSpecificType.Tracker;
break;
}
}
}
}
public void _LoadSpellDiminishInfo()
{
SpellDiminishInfo diminishInfo = new();
diminishInfo.DiminishGroup = DiminishingGroupCompute();
diminishInfo.DiminishReturnType = DiminishingTypeCompute(diminishInfo.DiminishGroup);
diminishInfo.DiminishMaxLevel = DiminishingMaxLevelCompute(diminishInfo.DiminishGroup);
diminishInfo.DiminishDurationLimit = DiminishingLimitDurationCompute();
_diminishInfo = diminishInfo;
}
public DiminishingGroup GetDiminishingReturnsGroupForSpell()
{
return _diminishInfo.DiminishGroup;
}
public DiminishingReturnsType GetDiminishingReturnsGroupType()
{
return _diminishInfo.DiminishReturnType;
}
public DiminishingLevels GetDiminishingReturnsMaxLevel()
{
return _diminishInfo.DiminishMaxLevel;
}
public int GetDiminishingReturnsLimitDuration()
{
return _diminishInfo.DiminishDurationLimit;
}
DiminishingGroup DiminishingGroupCompute()
{
if (IsPositive())
return DiminishingGroup.None;
if (HasAura(AuraType.ModTaunt))
return DiminishingGroup.Taunt;
switch (Id)
{
case 20549: // War Stomp (Racial - Tauren)
case 24394: // Intimidation
case 118345: // Pulverize (Primal Earth Elemental)
case 118905: // Static Charge (Capacitor Totem)
return DiminishingGroup.Stun;
case 107079: // Quaking Palm
return DiminishingGroup.Incapacitate;
case 155145: // Arcane Torrent (Racial - Blood Elf)
return DiminishingGroup.Silence;
case 108199: // Gorefiend's Grasp
case 191244: // Sticky Bomb
return DiminishingGroup.AOEKnockback;
default:
break;
}
// Explicit Diminishing Groups
switch (SpellFamilyName)
{
case SpellFamilyNames.Generic:
// Frost Tomb
if (Id == 48400)
return DiminishingGroup.None;
// Gnaw
else if (Id == 47481)
return DiminishingGroup.Stun;
// ToC Icehowl Arctic Breath
else if (Id == 66689)
return DiminishingGroup.None;
// Black Plague
else if (Id == 64155)
return DiminishingGroup.None;
// Screams of the Dead (King Ymiron)
else if (Id == 51750)
return DiminishingGroup.None;
// Crystallize (Keristrasza heroic)
else if (Id == 48179)
return DiminishingGroup.None;
break;
case SpellFamilyNames.Mage:
{
// Frost Nova -- 122
if (SpellFamilyFlags[0].HasAnyFlag(0x40u))
return DiminishingGroup.Root;
// Freeze (Water Elemental) -- 33395
if (SpellFamilyFlags[2].HasAnyFlag(0x200u))
return DiminishingGroup.Root;
// Dragon's Breath -- 31661
if (SpellFamilyFlags[0].HasAnyFlag(0x800000u))
return DiminishingGroup.Incapacitate;
// Polymorph -- 118
if (SpellFamilyFlags[0].HasAnyFlag(0x1000000u))
return DiminishingGroup.Incapacitate;
// Ring of Frost -- 82691
if (SpellFamilyFlags[2].HasAnyFlag(0x40u))
return DiminishingGroup.Incapacitate;
// Ice Nova -- 157997
if (SpellFamilyFlags[2].HasAnyFlag(0x800000u))
return DiminishingGroup.Incapacitate;
break;
}
case SpellFamilyNames.Warrior:
{
// Shockwave -- 132168
if (SpellFamilyFlags[1].HasAnyFlag(0x8000u))
return DiminishingGroup.Stun;
// Storm Bolt -- 132169
if (SpellFamilyFlags[2].HasAnyFlag(0x1000u))
return DiminishingGroup.Stun;
// Intimidating Shout -- 5246
if (SpellFamilyFlags[0].HasAnyFlag(0x40000u))
return DiminishingGroup.Disorient;
break;
}
case SpellFamilyNames.Warlock:
{
// Mortal Coil -- 6789
if (SpellFamilyFlags[0].HasAnyFlag(0x80000u))
return DiminishingGroup.Incapacitate;
// Banish -- 710
if (SpellFamilyFlags[1].HasAnyFlag(0x8000000u))
return DiminishingGroup.Incapacitate;
// Fear -- 118699
if (SpellFamilyFlags[1].HasAnyFlag(0x400u))
return DiminishingGroup.Disorient;
// Howl of Terror -- 5484
if (SpellFamilyFlags[1].HasAnyFlag(0x8u))
return DiminishingGroup.Disorient;
// Shadowfury -- 30283
if (SpellFamilyFlags[1].HasAnyFlag(0x1000u))
return DiminishingGroup.Stun;
// Summon Infernal -- 22703
if (SpellFamilyFlags[0].HasAnyFlag(0x1000u))
return DiminishingGroup.Stun;
// 170995 -- Cripple
if (Id == 170995)
return DiminishingGroup.LimitOnly;
break;
}
case SpellFamilyNames.WarlockPet:
{
// Fellash -- 115770
// Whiplash -- 6360
if (SpellFamilyFlags[0].HasAnyFlag(0x8000000u))
return DiminishingGroup.AOEKnockback;
// Mesmerize (Shivarra pet) -- 115268
// Seduction (Succubus pet) -- 6358
if (SpellFamilyFlags[0].HasAnyFlag(0x2000000u))
return DiminishingGroup.Disorient;
// Axe Toss (Felguard pet) -- 89766
if (SpellFamilyFlags[1].HasAnyFlag(0x4u))
return DiminishingGroup.Stun;
break;
}
case SpellFamilyNames.Druid:
{
// Maim -- 22570
if (SpellFamilyFlags[1].HasAnyFlag(0x80u))
return DiminishingGroup.Stun;
// Mighty Bash -- 5211
if (SpellFamilyFlags[0].HasAnyFlag(0x2000u))
return DiminishingGroup.Stun;
// Rake -- 163505 -- no flags on the stun
if (Id == 163505)
return DiminishingGroup.Stun;
// Incapacitating Roar -- 99, no flags on the stun, 14
if (SpellFamilyFlags[1].HasAnyFlag(0x1u))
return DiminishingGroup.Incapacitate;
// Cyclone -- 33786
if (SpellFamilyFlags[1].HasAnyFlag(0x20u))
return DiminishingGroup.Disorient;
// Solar Beam -- 81261
if (Id == 81261)
return DiminishingGroup.Silence;
// Typhoon -- 61391
if (SpellFamilyFlags[1].HasAnyFlag(0x1000000u))
return DiminishingGroup.AOEKnockback;
// Ursol's Vortex -- 118283, no family flags
if (Id == 118283)
return DiminishingGroup.AOEKnockback;
// Entangling Roots -- 339
if (SpellFamilyFlags[0].HasAnyFlag(0x200u))
return DiminishingGroup.Root;
// Mass Entanglement -- 102359
if (SpellFamilyFlags[2].HasAnyFlag(0x4u))
return DiminishingGroup.Root;
break;
}
case SpellFamilyNames.Rogue:
{
// Between the Eyes -- 199804
if (SpellFamilyFlags[0].HasAnyFlag(0x800000u))
return DiminishingGroup.Stun;
// Cheap Shot -- 1833
if (SpellFamilyFlags[0].HasAnyFlag(0x400u))
return DiminishingGroup.Stun;
// Kidney Shot -- 408
if (SpellFamilyFlags[0].HasAnyFlag(0x200000u))
return DiminishingGroup.Stun;
// Gouge -- 1776
if (SpellFamilyFlags[0].HasAnyFlag(0x8u))
return DiminishingGroup.Incapacitate;
// Sap -- 6770
if (SpellFamilyFlags[0].HasAnyFlag(0x80u))
return DiminishingGroup.Incapacitate;
// Blind -- 2094
if (SpellFamilyFlags[0].HasAnyFlag(0x1000000u))
return DiminishingGroup.Disorient;
// Garrote -- 1330
if (SpellFamilyFlags[1].HasAnyFlag(0x20000000u))
return DiminishingGroup.Silence;
break;
}
case SpellFamilyNames.Hunter:
{
// Charge (Tenacity pet) -- 53148, no flags
if (Id == 53148)
return DiminishingGroup.Root;
// Ranger's Net -- 200108
// Tracker's Net -- 212638
if (Id == 200108 || Id == 212638)
return DiminishingGroup.Root;
// Binding Shot -- 117526, no flags
if (Id == 117526)
return DiminishingGroup.Stun;
// Freezing Trap -- 3355
if (SpellFamilyFlags[0].HasAnyFlag(0x8u))
return DiminishingGroup.Incapacitate;
// Wyvern Sting -- 19386
if (SpellFamilyFlags[1].HasAnyFlag(0x1000u))
return DiminishingGroup.Incapacitate;
// Bursting Shot -- 224729
if (SpellFamilyFlags[2].HasAnyFlag(0x40u))
return DiminishingGroup.Disorient;
// Scatter Shot -- 213691
if (SpellFamilyFlags[2].HasAnyFlag(0x8000u))
return DiminishingGroup.Disorient;
// Spider Sting -- 202933
if (Id == 202933)
return DiminishingGroup.Silence;
break;
}
case SpellFamilyNames.Paladin:
{
// Repentance -- 20066
if (SpellFamilyFlags[0].HasAnyFlag(0x4u))
return DiminishingGroup.Incapacitate;
// Blinding Light -- 105421
if (Id == 105421)
return DiminishingGroup.Disorient;
// Avenger's Shield -- 31935
if (SpellFamilyFlags[0].HasAnyFlag(0x4000u))
return DiminishingGroup.Silence;
// Hammer of Justice -- 853
if (SpellFamilyFlags[0].HasAnyFlag(0x800u))
return DiminishingGroup.Stun;
break;
}
case SpellFamilyNames.Shaman:
{
// Hex -- 51514
// Hex -- 196942 (Voodoo Totem)
if (SpellFamilyFlags[1].HasAnyFlag(0x8000u))
return DiminishingGroup.Incapacitate;
// Thunderstorm -- 51490
if (SpellFamilyFlags[1].HasAnyFlag(0x2000u))
return DiminishingGroup.AOEKnockback;
// Earthgrab Totem -- 64695
if (SpellFamilyFlags[2].HasAnyFlag(0x4000u))
return DiminishingGroup.Root;
// Lightning Lasso -- 204437
if (SpellFamilyFlags[3].HasAnyFlag(0x2000000u))
return DiminishingGroup.Stun;
break;
}
case SpellFamilyNames.Deathknight:
{
// Chains of Ice -- 96294
if (Id == 96294)
return DiminishingGroup.Root;
// Blinding Sleet -- 207167
if (Id == 207167)
return DiminishingGroup.Disorient;
// Strangulate -- 47476
if (SpellFamilyFlags[0].HasAnyFlag(0x200u))
return DiminishingGroup.Silence;
// Asphyxiate -- 108194
if (SpellFamilyFlags[2].HasAnyFlag(0x100000u))
return DiminishingGroup.Stun;
// Gnaw (Ghoul) -- 91800, no flags
if (Id == 91800)
return DiminishingGroup.Stun;
// Monstrous Blow (Ghoul w/ Dark Transformation active) -- 91797
if (Id == 91797)
return DiminishingGroup.Stun;
// Winter is Coming -- 207171
if (Id == 207171)
return DiminishingGroup.Stun;
break;
}
case SpellFamilyNames.Priest:
{
// Holy Word: Chastise -- 200200
if (SpellFamilyFlags[2].HasAnyFlag(0x20u) && GetSpellVisual() == 52021)
return DiminishingGroup.Stun;
// Mind Bomb -- 226943
if (Id == 226943)
return DiminishingGroup.Stun;
// Mind Control -- 605
if (SpellFamilyFlags[0].HasAnyFlag(0x20000u) && GetSpellVisual() == 39068)
return DiminishingGroup.Incapacitate;
// Holy Word: Chastise -- 200196
if (SpellFamilyFlags[2].HasAnyFlag(0x20u) && GetSpellVisual() == 52019)
return DiminishingGroup.Incapacitate;
// Psychic Scream -- 8122
if (SpellFamilyFlags[0].HasAnyFlag(0x10000u))
return DiminishingGroup.Disorient;
// Silence -- 15487
if (SpellFamilyFlags[1].HasAnyFlag(0x200000u) && GetSpellVisual() == 39025)
return DiminishingGroup.Silence;
// Shining Force -- 204263
if (Id == 204263)
return DiminishingGroup.AOEKnockback;
break;
}
case SpellFamilyNames.Monk:
{
// Disable -- 116706, no flags
if (Id == 116706)
return DiminishingGroup.Root;
// Fists of Fury -- 120086
if (SpellFamilyFlags[1].HasAnyFlag(0x800000u) && !SpellFamilyFlags[2].HasAnyFlag(0x8u))
return DiminishingGroup.Stun;
// Leg Sweep -- 119381
if (SpellFamilyFlags[1].HasAnyFlag(0x200u))
return DiminishingGroup.Stun;
// Incendiary Breath (honor talent) -- 202274, no flags
if (Id == 202274)
return DiminishingGroup.Incapacitate;
// Paralysis -- 115078
if (SpellFamilyFlags[2].HasAnyFlag(0x800000u))
return DiminishingGroup.Incapacitate;
// Song of Chi-Ji -- 198909
if (Id == 198909)
return DiminishingGroup.Disorient;
break;
}
case SpellFamilyNames.DemonHunter:
switch (Id)
{
case 179057: // Chaos Nova
case 211881: // Fel Eruption
case 200166: // Metamorphosis
case 205630: // Illidan's Grasp
return DiminishingGroup.Stun;
case 217832: // Imprison
case 221527: // Imprison
return DiminishingGroup.Incapacitate;
default:
break;
}
break;
default:
break;
}
return DiminishingGroup.None;
}
DiminishingReturnsType DiminishingTypeCompute(DiminishingGroup group)
{
switch (group)
{
case DiminishingGroup.Taunt:
case DiminishingGroup.Stun:
return DiminishingReturnsType.All;
case DiminishingGroup.LimitOnly:
case DiminishingGroup.None:
return DiminishingReturnsType.None;
default:
return DiminishingReturnsType.Player;
}
}
DiminishingLevels DiminishingMaxLevelCompute(DiminishingGroup group)
{
switch (group)
{
case DiminishingGroup.Taunt:
return DiminishingLevels.TauntImmune;
case DiminishingGroup.AOEKnockback:
return DiminishingLevels.Level2;
default:
return DiminishingLevels.Immune;
}
}
int DiminishingLimitDurationCompute()
{
// Explicit diminishing duration
switch (SpellFamilyName)
{
case SpellFamilyNames.Mage:
// Dragon's Breath - 3 seconds in PvP
if (SpellFamilyFlags[0].HasAnyFlag(0x800000u))
return 3 * Time.InMilliseconds;
break;
case SpellFamilyNames.Warlock:
// Cripple - 4 seconds in PvP
if (Id == 170995)
return 4 * Time.InMilliseconds;
break;
case SpellFamilyNames.Hunter:
// Binding Shot - 3 seconds in PvP
if (Id == 117526)
return 3 * Time.InMilliseconds;
// Wyvern Sting - 6 seconds in PvP
if (SpellFamilyFlags[1].HasAnyFlag(0x1000u))
return 6 * Time.InMilliseconds;
break;
case SpellFamilyNames.Monk:
// Paralysis - 4 seconds in PvP regardless of if they are facing you
if (SpellFamilyFlags[2].HasAnyFlag(0x800000u))
return 4 * Time.InMilliseconds;
break;
case SpellFamilyNames.DemonHunter:
switch (Id)
{
case 217832: // Imprison
case 221527: // Imprison
return 4 * Time.InMilliseconds;
default:
break;
}
break;
default:
break;
}
return 8 * Time.InMilliseconds;
}
public void _LoadImmunityInfo()
{
foreach (SpellEffectInfo effect in _effects)
{
uint schoolImmunityMask = 0;
uint applyHarmfulAuraImmunityMask = 0;
ulong mechanicImmunityMask = 0;
uint dispelImmunityMask = 0;
uint damageImmunityMask = 0;
byte otherImmunityMask = 0;
int miscVal = effect.MiscValue;
ImmunityInfo immuneInfo = effect.GetImmunityInfo();
switch (effect.ApplyAuraName)
{
case AuraType.MechanicImmunityMask:
{
CreatureImmunities creatureImmunities = Global.SpellMgr.GetCreatureImmunities(miscVal);
if (creatureImmunities != null)
{
schoolImmunityMask |= creatureImmunities.School.ToUInt();
dispelImmunityMask |= creatureImmunities.DispelType.ToUInt();
mechanicImmunityMask |= creatureImmunities.Mechanic.ToUInt();
otherImmunityMask |= (byte)creatureImmunities.Other;
foreach (SpellEffectName effectType in creatureImmunities.Effect)
immuneInfo.SpellEffectImmune.Add(effectType);
foreach (AuraType aura in creatureImmunities.Aura)
immuneInfo.AuraTypeImmune.Add(aura);
}
break;
}
case AuraType.MechanicImmunity:
{
switch (Id)
{
case 42292: // PvP trinket
case 59752: // Every Man for Himself
mechanicImmunityMask |= (ulong)Mechanics.ImmuneToMovementImpairmentAndLossControlMask;
immuneInfo.AuraTypeImmune.Add(AuraType.UseNormalMovementSpeed);
break;
case 34471: // The Beast Within
case 19574: // Bestial Wrath
case 46227: // Medallion of Immunity
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 |= (ulong)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)
break;
mechanicImmunityMask |= 1ul << 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:
{
dispelImmunityMask = 1u << miscVal;
break;
}
default:
break;
}
immuneInfo.SchoolImmuneMask = schoolImmunityMask;
immuneInfo.ApplyHarmfulAuraImmuneMask = applyHarmfulAuraImmunityMask;
immuneInfo.MechanicImmuneMask = mechanicImmunityMask;
immuneInfo.DispelImmuneMask = dispelImmunityMask;
immuneInfo.DamageSchoolMask = damageImmunityMask;
immuneInfo.OtherImmuneMask = otherImmunityMask;
_allowedMechanicMask |= immuneInfo.MechanicImmuneMask;
}
if (HasAttribute(SpellAttr5.AllowWhileStunned))
{
switch (Id)
{
case 22812: // Barkskin
case 47585: // Dispersion
_allowedMechanicMask |=
(1 << (int)Mechanics.Stun) |
(1 << (int)Mechanics.Freeze) |
(1 << (int)Mechanics.Knockout) |
(1 << (int)Mechanics.Sleep);
break;
case 49039: // Lichborne, don't allow normal stuns
break;
default:
_allowedMechanicMask |= (1 << (int)Mechanics.Stun);
break;
}
}
if (HasAttribute(SpellAttr5.AllowWhileConfused))
_allowedMechanicMask |= (1 << (int)Mechanics.Disoriented);
if (HasAttribute(SpellAttr5.AllowWhileFleeing))
{
switch (Id)
{
case 22812: // Barkskin
case 47585: // Dispersion
_allowedMechanicMask |= (1 << (int)Mechanics.Fear) | (1 << (int)Mechanics.Horror);
break;
default:
_allowedMechanicMask |= (1 << (int)Mechanics.Fear);
break;
}
}
}
void _LoadSqrtTargetLimit(int maxTargets, int numNonDiminishedTargets, uint? maxTargetsEffectValueHolder, uint? numNonDiminishedTargetsEffectValueHolder)
{
SqrtDamageAndHealingDiminishing.MaxTargets = maxTargets;
SqrtDamageAndHealingDiminishing.NumNonDiminishedTargets = numNonDiminishedTargets;
if (maxTargetsEffectValueHolder.HasValue)
{
if (maxTargetsEffectValueHolder < GetEffects().Count)
{
SpellEffectInfo valueHolder = GetEffect(maxTargetsEffectValueHolder.Value);
int expectedValue = valueHolder.CalcBaseValue(null, null, 0, -1);
if (maxTargets != expectedValue)
Log.outError(LogFilter.Spells, $"SpellInfo::_LoadSqrtTargetLimit(maxTargets): Spell {Id} has different value in effect {maxTargetsEffectValueHolder.Value} than expected, recheck target caps (expected {maxTargets}, got {expectedValue})");
}
else
Log.outError(LogFilter.Spells, $"SpellInfo::_LoadSqrtTargetLimit(maxTargets): Spell {Id} does not have effect {maxTargetsEffectValueHolder.Value}");
}
if (numNonDiminishedTargetsEffectValueHolder.HasValue)
{
if (numNonDiminishedTargetsEffectValueHolder < GetEffects().Count)
{
SpellEffectInfo valueHolder = GetEffect(numNonDiminishedTargetsEffectValueHolder.Value);
int expectedValue = valueHolder.CalcBaseValue(null, null, 0, -1);
if (numNonDiminishedTargets != expectedValue)
Log.outError(LogFilter.Spells, $"SpellInfo::_LoadSqrtTargetLimit(numNonDiminishedTargets): Spell {Id} has different value in effect {numNonDiminishedTargetsEffectValueHolder.Value} than expected, recheck target caps (expected {numNonDiminishedTargets}, got {expectedValue})");
}
else
Log.outError(LogFilter.Spells, $"SpellInfo::_LoadSqrtTargetLimit(numNonDiminishedTargets): Spell {Id} does not have effect {numNonDiminishedTargetsEffectValueHolder.Value}");
}
}
public void ApplyAllSpellImmunitiesTo(Unit target, SpellEffectInfo spellEffectInfo, bool apply)
{
ImmunityInfo immuneInfo = spellEffectInfo.GetImmunityInfo();
uint schoolImmunity = immuneInfo.SchoolImmuneMask;
if (schoolImmunity != 0)
{
target.ApplySpellImmune(Id, SpellImmunity.School, schoolImmunity, apply);
if (apply && HasAttribute(SpellAttr1.ImmunityPurgesEffect))
{
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
});
}
if (apply && (schoolImmunity & (uint)SpellSchoolMask.Normal) != 0)
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.InvulnerabilityBuff);
}
ulong mechanicImmunity = immuneInfo.MechanicImmuneMask;
if (mechanicImmunity != 0)
{
for (uint i = 0; i < (int)Mechanics.Max; ++i)
if (Convert.ToBoolean(mechanicImmunity & (1ul << (int)i)))
target.ApplySpellImmune(Id, SpellImmunity.Mechanic, i, apply);
if (HasAttribute(SpellAttr1.ImmunityPurgesEffect))
{
// exception for purely snare mechanic (eg. hands of freedom)!
if (apply)
target.RemoveAurasWithMechanic(mechanicImmunity, AuraRemoveMode.Default, Id);
else
{
List<Aura> aurasToUpdateTargets = new();
target.RemoveAppliedAuras(aurApp =>
{
Aura aura = aurApp.GetBase();
if ((aura.GetSpellInfo().GetAllEffectsMechanicMask() & mechanicImmunity) != 0)
aurasToUpdateTargets.Add(aura);
// only update targets, don't remove anything
return false;
});
foreach (Aura aura in aurasToUpdateTargets)
aura.UpdateTargetMap(aura.GetCaster());
}
}
}
uint dispelImmunity = immuneInfo.DispelImmuneMask;
if (dispelImmunity != 0)
{
for (int i = 0; i < (int)DispelType.Max; ++i)
if ((dispelImmunity & (1u << i)) != 0)
target.ApplySpellImmune(Id, SpellImmunity.Dispel, (uint)i, apply);
if (apply && HasAttribute(SpellAttr1.ImmunityPurgesEffect))
{
target.RemoveAppliedAuras(aurApp =>
{
SpellInfo spellInfo = aurApp.GetBase().GetSpellInfo();
uint dispelMask = spellInfo.GetDispelMask();
if ((dispelMask & dispelImmunity) == dispelMask)
return true;
return false;
});
}
}
uint damageImmunity = immuneInfo.DamageSchoolMask;
if (damageImmunity != 0)
{
target.ApplySpellImmune(Id, SpellImmunity.Damage, damageImmunity, apply);
if (apply && (damageImmunity & (uint)SpellSchoolMask.Normal) != 0)
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.InvulnerabilityBuff);
}
foreach (AuraType auraType in immuneInfo.AuraTypeImmune)
{
target.ApplySpellImmune(Id, SpellImmunity.State, auraType, apply);
if (apply && HasAttribute(SpellAttr1.ImmunityPurgesEffect))
{
target.RemoveAurasByType(auraType, aurApp =>
{
// if the aura has SPELL_ATTR0_NO_IMMUNITIES, then it cannot be removed by immunity
return !aurApp.GetBase().GetSpellInfo().HasAttribute(SpellAttr0.NoImmunities);
});
}
}
foreach (SpellEffectName effectType in immuneInfo.SpellEffectImmune)
target.ApplySpellImmune(Id, SpellImmunity.Effect, effectType, apply);
byte otherImmuneMask = immuneInfo.OtherImmuneMask;
if (otherImmuneMask != 0)
target.ApplySpellImmune(Id, SpellImmunity.Other, otherImmuneMask, apply);
}
bool CanSpellProvideImmunityAgainstAura(SpellInfo auraSpellInfo)
{
if (auraSpellInfo == null)
return false;
foreach (var effectInfo in _effects)
{
if (!effectInfo.IsEffect())
continue;
ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo();
if (!auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && !auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
{
uint schoolImmunity = immuneInfo.SchoolImmuneMask;
if (schoolImmunity != 0)
if (((uint)auraSpellInfo.SchoolMask & schoolImmunity) != 0)
return true;
}
ulong mechanicImmunity = immuneInfo.MechanicImmuneMask;
if (mechanicImmunity != 0)
if ((mechanicImmunity & (1ul << (int)auraSpellInfo.Mechanic)) != 0)
return true;
uint dispelImmunity = immuneInfo.DispelImmuneMask;
if (dispelImmunity != 0)
if ((uint)auraSpellInfo.Dispel == dispelImmunity)
return true;
bool immuneToAllEffects = true;
foreach (var auraSpellEffectInfo in auraSpellInfo.GetEffects())
{
if (!auraSpellEffectInfo.IsEffect())
continue;
if (!immuneInfo.SpellEffectImmune.Contains(auraSpellEffectInfo.Effect))
{
immuneToAllEffects = false;
break;
}
uint mechanic = (uint)auraSpellEffectInfo.Mechanic;
if (mechanic != 0)
{
if (!Convert.ToBoolean(immuneInfo.MechanicImmuneMask & (1ul << (int)mechanic)))
{
immuneToAllEffects = false;
break;
}
}
if (!auraSpellInfo.HasAttribute(SpellAttr3.AlwaysHit))
{
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.NoSchoolImmunities))
{
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;
}
public bool SpellCancelsAuraEffect(AuraEffect aurEff)
{
if (!HasAttribute(SpellAttr1.ImmunityPurgesEffect))
return false;
if (aurEff.GetSpellInfo().HasAttribute(SpellAttr0.NoImmunities))
return false;
foreach (var effectInfo in GetEffects())
{
if (!effectInfo.IsEffect(SpellEffectName.ApplyAura))
continue;
uint miscValue = (uint)effectInfo.MiscValue;
switch (effectInfo.ApplyAuraName)
{
case AuraType.StateImmunity:
if (miscValue != (uint)aurEff.GetAuraType())
continue;
break;
case AuraType.SchoolImmunity:
case AuraType.ModImmuneAuraApplySchool:
if (aurEff.GetSpellInfo().HasAttribute(SpellAttr2.NoSchoolImmunities) || !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 ulong GetAllowedMechanicMask()
{
return _allowedMechanicMask;
}
public ulong GetMechanicImmunityMask(Unit caster)
{
ulong casterMechanicImmunityMask = caster.GetMechanicImmunityMask();
ulong mechanicImmunityMask = 0;
if (CanBeInterrupted(null, caster, true))
{
if ((casterMechanicImmunityMask & (1 << (int)Mechanics.Silence)) != 0)
mechanicImmunityMask |= (1 << (int)Mechanics.Silence);
if ((casterMechanicImmunityMask & (1 << (int)Mechanics.Interrupt)) != 0)
mechanicImmunityMask |= (1 << (int)Mechanics.Interrupt);
}
return mechanicImmunityMask;
}
public float GetMinRange(bool positive = false)
{
if (RangeEntry == null)
return 0.0f;
return RangeEntry.RangeMin[positive ? 1 : 0];
}
public float GetMaxRange(bool positive = false, WorldObject caster = null, Spell spell = null)
{
if (RangeEntry == null)
return 0.0f;
float range = RangeEntry.RangeMax[positive ? 1 : 0];
if (caster != null)
{
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(this, SpellModOp.Range, ref range, spell);
}
return range;
}
public int CalcDuration(WorldObject caster = null)
{
int duration = GetDuration();
if (caster != null)
{
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(this, SpellModOp.Duration, ref duration);
}
return duration;
}
public int GetDuration()
{
if (DurationEntry == null)
return IsPassive() ? -1 : 0;
return (DurationEntry.Duration == -1) ? -1 : Math.Abs(DurationEntry.Duration);
}
public int GetMaxDuration()
{
if (DurationEntry == null)
return IsPassive() ? -1 : 0;
return (DurationEntry.MaxDuration == -1) ? -1 : Math.Abs(DurationEntry.MaxDuration);
}
public int CalcCastTime(Spell spell = null)
{
int castTime = 0;
if (CastTimeEntry != null)
castTime = Math.Max(CastTimeEntry.Base, CastTimeEntry.Minimum);
if (castTime <= 0)
return 0;
if (spell != null)
spell.GetCaster().ModSpellCastTime(this, ref castTime, spell);
if (HasAttribute(SpellAttr0.UsesRangedSlot) && (!IsAutoRepeatRangedSpell()) && !HasAttribute(SpellAttr9.CooldownIgnoresRangedWeapon))
castTime += 500;
return (castTime > 0) ? castTime : 0;
}
public uint GetMaxTicks()
{
uint totalTicks = 0;
int DotDuration = GetDuration();
foreach (var effectInfo in GetEffects())
{
if (!effectInfo.IsEffect(SpellEffectName.ApplyAura))
continue;
switch (effectInfo.ApplyAuraName)
{
case AuraType.PeriodicDamage:
case AuraType.PeriodicDamagePercent:
case AuraType.PeriodicHeal:
case AuraType.ObsModHealth:
case AuraType.ObsModPower:
case AuraType.PeriodicTriggerSpellFromClient:
case AuraType.PowerBurn:
case AuraType.PeriodicLeech:
case AuraType.PeriodicManaLeech:
case AuraType.PeriodicEnergize:
case AuraType.PeriodicDummy:
case AuraType.PeriodicTriggerSpell:
case AuraType.PeriodicTriggerSpellWithValue:
case AuraType.PeriodicHealthFunnel:
// skip infinite periodics
if (effectInfo.ApplyAuraPeriod > 0 && DotDuration > 0)
{
totalTicks = (uint)DotDuration / effectInfo.ApplyAuraPeriod;
if (HasAttribute(SpellAttr5.ExtraInitialPeriod))
++totalTicks;
}
break;
}
}
return totalTicks;
}
public uint GetRecoveryTime()
{
return RecoveryTime > CategoryRecoveryTime ? RecoveryTime : CategoryRecoveryTime;
}
public SpellPowerCost CalcPowerCost(PowerType powerType, bool optionalCost, WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
{
// gameobject casts don't use power
Unit unitCaster = caster.ToUnit();
if (unitCaster == null)
return null;
var spellPowerRecord = PowerCosts.FirstOrDefault(spellPowerEntry => spellPowerEntry?.PowerType == powerType);
if (spellPowerRecord == null)
return null;
return CalcPowerCost(spellPowerRecord, optionalCost, caster, schoolMask, spell);
}
public SpellPowerCost CalcPowerCost(SpellPowerRecord power, bool optionalCost, WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
{
// gameobject casts don't use power
Unit unitCaster = caster.ToUnit();
if (unitCaster == null)
return null;
if (power.RequiredAuraSpellID != 0 && !unitCaster.HasAura(power.RequiredAuraSpellID))
return null;
// Spell drain all exist power on cast (Only paladin lay of Hands)
if (HasAttribute(SpellAttr1.UseAllMana))
{
if (optionalCost)
return null;
// If power type - health drain all
if (power.PowerType == PowerType.Health)
return new SpellPowerCost() { Power = PowerType.Health, Amount = (int)unitCaster.GetHealth() };
// Else drain all power
if (power.PowerType < PowerType.Max)
return new SpellPowerCost() { Power = power.PowerType, Amount = unitCaster.GetPower(power.PowerType) };
Log.outError(LogFilter.Spells, $"SpellInfo.CalcPowerCost: Unknown power type '{power.PowerType}' in spell {Id}");
return default;
}
// Base powerCost
int powerCost = 0;
if (!optionalCost)
{
powerCost = power.ManaCost;
// PCT cost from total amount
if (power.PowerCostPct != 0)
{
switch (power.PowerType)
{
// health as power used
case PowerType.Health:
if (MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f))
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetMaxHealth(), power.PowerCostMaxPct);
else
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetMaxHealth(), power.PowerCostPct);
break;
case PowerType.Mana:
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetCreateMana(), power.PowerCostPct);
break;
case PowerType.AlternatePower:
Log.outError(LogFilter.Spells, $"SpellInfo.CalcPowerCost: Unknown power type '{power.PowerType}' in spell {Id}");
return null;
default:
{
PowerTypeRecord powerTypeEntry = Global.DB2Mgr.GetPowerTypeEntry(power.PowerType);
if (powerTypeEntry != null)
{
powerCost += MathFunctions.CalculatePct(powerTypeEntry.MaxBasePower, power.PowerCostPct);
break;
}
Log.outError(LogFilter.Spells, $"SpellInfo.CalcPowerCost: Unknown power type '{power.PowerType}' in spell {Id}");
return null;
}
}
}
}
else
{
powerCost = (int)power.OptionalCost;
if (power.OptionalCostPct != 0)
{
switch (power.PowerType)
{
// health as power used
case PowerType.Health:
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetMaxHealth(), power.OptionalCostPct);
break;
case PowerType.Mana:
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetCreateMana(), power.OptionalCostPct);
break;
case PowerType.AlternatePower:
Log.outError(LogFilter.Spells, $"SpellInfo::CalcPowerCost: Unsupported power type POWER_ALTERNATE_POWER in spell {Id} for optional cost percent");
return null;
default:
{
var powerTypeEntry = Global.DB2Mgr.GetPowerTypeEntry(power.PowerType);
if (powerTypeEntry != null)
{
powerCost += (int)MathFunctions.CalculatePct(powerTypeEntry.MaxBasePower, power.OptionalCostPct);
break;
}
Log.outError(LogFilter.Spells, $"SpellInfo::CalcPowerCost: Unknown power type '{power.PowerType}' in spell {Id} for optional cost percent");
return null;
}
}
}
powerCost += unitCaster.GetTotalAuraModifier(AuraType.ModAdditionalPowerCost, aurEff =>
{
return aurEff.GetMiscValue() == (int)power.PowerType && aurEff.IsAffectingSpell(this);
});
}
bool initiallyNegative = powerCost < 0;
// Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
if (HasAttribute(SpellAttr4.WeaponSpeedCostScaling))
{
uint speed = 0;
SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(unitCaster.GetShapeshiftForm());
if (ss != null)
speed = ss.CombatRoundTime;
else
{
WeaponAttackType slot = WeaponAttackType.BaseAttack;
if (!HasAttribute(SpellAttr3.RequiresMainHandWeapon) && HasAttribute(SpellAttr3.RequiresOffHandWeapon))
slot = WeaponAttackType.OffAttack;
speed = unitCaster.GetBaseAttackTime(slot);
}
powerCost += (int)speed / 100;
}
if (power.PowerType != PowerType.Health)
{
if (!optionalCost)
{
// Flat mod from caster auras by spell school and power type
foreach (AuraEffect aura in unitCaster.GetAuraEffectsByType(AuraType.ModPowerCostSchool))
{
if ((aura.GetMiscValue() & (int)schoolMask) == 0)
continue;
if ((aura.GetMiscValueB() & (1 << (int)power.PowerType)) == 0)
continue;
powerCost += aura.GetAmount();
}
}
// PCT mod from user auras by spell school and power type
foreach (var schoolCostPct in unitCaster.GetAuraEffectsByType(AuraType.ModPowerCostSchoolPct))
{
if ((schoolCostPct.GetMiscValue() & (int)schoolMask) == 0)
continue;
if ((schoolCostPct.GetMiscValueB() & (1 << (int)power.PowerType)) == 0)
continue;
powerCost += MathFunctions.CalculatePct(powerCost, schoolCostPct.GetAmount());
}
}
// Apply cost mod by spell
Player modOwner = unitCaster.GetSpellModOwner();
if (modOwner != null)
{
SpellModOp mod = SpellModOp.Max;
switch (power.OrderIndex)
{
case 0:
mod = SpellModOp.PowerCost0;
break;
case 1:
mod = SpellModOp.PowerCost1;
break;
case 2:
mod = SpellModOp.PowerCost2;
break;
default:
break;
}
if (mod != SpellModOp.Max)
{
if (!optionalCost)
modOwner.ApplySpellMod(this, mod, ref powerCost, spell);
else
{
// optional cost ignores flat modifiers
int flatMod = 0;
float pctMod = 1.0f;
modOwner.GetSpellModValues(this, mod, spell, powerCost, ref flatMod, ref pctMod);
powerCost = (int)(powerCost * pctMod);
}
}
}
if (!unitCaster.IsControlledByPlayer() && MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f) && SpellLevel != 0 && power.PowerType == PowerType.Mana)
{
if (HasAttribute(SpellAttr0.ScalesWithCreatureLevel))
{
GtNpcManaCostScalerRecord spellScaler = CliDB.NpcManaCostScalerGameTable.GetRow(SpellLevel);
GtNpcManaCostScalerRecord casterScaler = CliDB.NpcManaCostScalerGameTable.GetRow(unitCaster.GetLevel());
if (spellScaler != null && casterScaler != null)
powerCost *= (int)(casterScaler.Scaler / spellScaler.Scaler);
}
}
if (power.PowerType == PowerType.Mana)
powerCost = (int)((float)powerCost * (1.0f + unitCaster.m_unitData.ManaCostMultiplier));
// power cost cannot become negative if initially positive
if (initiallyNegative != (powerCost < 0))
powerCost = 0;
return new SpellPowerCost() { Power = power.PowerType, Amount = powerCost };
}
public List<SpellPowerCost> CalcPowerCost(WorldObject caster, SpellSchoolMask schoolMask, Spell spell = null)
{
List<SpellPowerCost> costs = new();
if (caster.IsUnit())
{
SpellPowerCost getOrCreatePowerCost(PowerType powerType)
{
var itr = costs.Find(cost => cost.Power == powerType);
if (itr != null)
return itr;
costs.Add(new SpellPowerCost() { Power = powerType, Amount = 0 });
return costs.Last();
}
foreach (SpellPowerRecord power in PowerCosts)
{
if (power == null)
continue;
SpellPowerCost cost = CalcPowerCost(power, false, caster, schoolMask, spell);
if (cost != null)
getOrCreatePowerCost(cost.Power).Amount += cost.Amount;
SpellPowerCost optionalCost = CalcPowerCost(power, true, caster, schoolMask, spell);
if (optionalCost != null)
{
SpellPowerCost cost1 = getOrCreatePowerCost(optionalCost.Power);
int remainingPower = caster.ToUnit().GetPower(optionalCost.Power) - cost1.Amount;
if (remainingPower > 0)
cost1.Amount += Math.Min(optionalCost.Amount, remainingPower);
}
}
}
return costs;
}
float CalcPPMHasteMod(SpellProcsPerMinuteModRecord mod, Unit caster)
{
float haste = caster.m_unitData.ModHaste;
float rangedHaste = caster.m_unitData.ModRangedHaste;
float spellHaste = caster.m_unitData.ModSpellHaste;
float regenHaste = caster.m_unitData.ModHasteRegen;
switch (mod.Param)
{
case 1:
return (1.0f / haste - 1.0f) * mod.Coeff;
case 2:
return (1.0f / rangedHaste - 1.0f) * mod.Coeff;
case 3:
return (1.0f / spellHaste - 1.0f) * mod.Coeff;
case 4:
return (1.0f / regenHaste - 1.0f) * mod.Coeff;
case 5:
return (1.0f / Math.Min(Math.Min(Math.Min(haste, rangedHaste), spellHaste), regenHaste) - 1.0f) * mod.Coeff;
default:
break;
}
return 0.0f;
}
float CalcPPMCritMod(SpellProcsPerMinuteModRecord mod, Unit caster)
{
Player player = caster.ToPlayer();
if (player == null)
return 0.0f;
float crit = player.m_activePlayerData.CritPercentage;
float rangedCrit = player.m_activePlayerData.RangedCritPercentage;
float spellCrit = player.m_activePlayerData.SpellCritPercentage;
switch (mod.Param)
{
case 1:
return crit * mod.Coeff * 0.01f;
case 2:
return rangedCrit * mod.Coeff * 0.01f;
case 3:
return spellCrit * mod.Coeff * 0.01f;
case 4:
return Math.Min(Math.Min(crit, rangedCrit), spellCrit) * mod.Coeff * 0.01f;
default:
break;
}
return 0.0f;
}
float CalcPPMItemLevelMod(SpellProcsPerMinuteModRecord mod, int itemLevel)
{
if (itemLevel == mod.Param)
return 0.0f;
float itemLevelPoints = ItemEnchantmentManager.GetRandomPropertyPoints((uint)itemLevel, ItemQuality.Rare, InventoryType.Chest, 0);
float basePoints = ItemEnchantmentManager.GetRandomPropertyPoints(mod.Param, ItemQuality.Rare, InventoryType.Chest, 0);
if (itemLevelPoints == basePoints)
return 0.0f;
return ((itemLevelPoints / basePoints) - 1.0f) * mod.Coeff;
}
public float CalcProcPPM(Unit caster, int itemLevel)
{
float ppm = ProcBasePPM;
if (caster == null)
return ppm;
foreach (SpellProcsPerMinuteModRecord mod in ProcPPMMods)
{
switch (mod.Type)
{
case SpellProcsPerMinuteModType.Haste:
{
ppm *= 1.0f + CalcPPMHasteMod(mod, caster);
break;
}
case SpellProcsPerMinuteModType.Crit:
{
ppm *= 1.0f + CalcPPMCritMod(mod, caster);
break;
}
case SpellProcsPerMinuteModType.Class:
{
if (caster.GetClassMask().HasAnyFlag(mod.Param))
ppm *= 1.0f + mod.Coeff;
break;
}
case SpellProcsPerMinuteModType.Spec:
{
Player plrCaster = caster.ToPlayer();
if (plrCaster != null)
if (plrCaster.GetPrimarySpecialization() == (ChrSpecialization)mod.Param)
ppm *= 1.0f + mod.Coeff;
break;
}
case SpellProcsPerMinuteModType.Race:
{
if ((caster.GetRaceMask() & mod.Param) != 0)
ppm *= 1.0f + mod.Coeff;
break;
}
case SpellProcsPerMinuteModType.ItemLevel:
{
ppm *= 1.0f + CalcPPMItemLevelMod(mod, itemLevel);
break;
}
case SpellProcsPerMinuteModType.Battleground:
{
if (caster.GetMap().IsBattlegroundOrArena())
ppm *= 1.0f + mod.Coeff;
break;
}
default:
break;
}
}
return ppm;
}
public bool IsRanked()
{
return ChainEntry != null;
}
public byte GetRank()
{
if (ChainEntry == null)
return 1;
return ChainEntry.rank;
}
public SpellInfo GetFirstRankSpell()
{
if (ChainEntry == null)
return this;
return ChainEntry.first;
}
SpellInfo GetLastRankSpell()
{
if (ChainEntry == null)
return null;
return ChainEntry.last;
}
public SpellInfo GetNextRankSpell()
{
if (ChainEntry == null)
return null;
return ChainEntry.next;
}
SpellInfo GetPrevRankSpell()
{
if (ChainEntry == null)
return null;
return ChainEntry.prev;
}
public SpellInfo GetAuraRankForLevel(uint level)
{
// ignore passive spells
if (IsPassive())
return this;
// Client ignores spell with these attributes (sub_53D9D0)
if (HasAttribute(SpellAttr0.AuraIsDebuff) || HasAttribute(SpellAttr2.AllowLowLevelBuff) || HasAttribute(SpellAttr3.OnlyProcOnCaster))
return this;
bool needRankSelection = false;
foreach (var effectInfo in GetEffects())
{
if (IsPositiveEffect(effectInfo.EffectIndex) &&
(effectInfo.IsEffect(SpellEffectName.ApplyAura) ||
effectInfo.IsEffect(SpellEffectName.ApplyAreaAuraParty) ||
effectInfo.IsEffect(SpellEffectName.ApplyAreaAuraRaid)) &&
effectInfo.Scaling.Coefficient != 0)
{
needRankSelection = true;
break;
}
}
// not required
if (!needRankSelection)
return this;
for (SpellInfo nextSpellInfo = this; nextSpellInfo != null; nextSpellInfo = nextSpellInfo.GetPrevRankSpell())
{
// if found appropriate level
if ((level + 10) >= nextSpellInfo.SpellLevel)
return nextSpellInfo;
// one rank less then
}
// not found
return null;
}
public bool IsRankOf(SpellInfo spellInfo)
{
return GetFirstRankSpell() == spellInfo.GetFirstRankSpell();
}
public bool IsDifferentRankOf(SpellInfo spellInfo)
{
if (Id == spellInfo.Id)
return false;
return IsRankOf(spellInfo);
}
public bool IsHighRankOf(SpellInfo spellInfo)
{
if (ChainEntry != null && spellInfo.ChainEntry != null)
{
if (ChainEntry.first == spellInfo.ChainEntry.first)
if (ChainEntry.rank > spellInfo.ChainEntry.rank)
return true;
}
return false;
}
public uint GetSpellXSpellVisualId(WorldObject caster = null, WorldObject viewer = null)
{
foreach (SpellXSpellVisualRecord visual in _visuals)
{
if (visual.CasterPlayerConditionID != 0)
if (caster == null || !caster.IsPlayer() || !ConditionManager.IsPlayerMeetingCondition(caster.ToPlayer(), visual.CasterPlayerConditionID))
continue;
var unitCondition = CliDB.UnitConditionStorage.LookupByKey(visual.CasterUnitConditionID);
if (unitCondition != null)
if (caster == null || !caster.IsUnit() || !ConditionManager.IsUnitMeetingCondition(caster.ToUnit(), viewer?.ToUnit(), unitCondition))
continue;
return visual.Id;
}
return 0;
}
public uint GetSpellVisual(WorldObject caster = null, WorldObject viewer = null)
{
var visual = CliDB.SpellXSpellVisualStorage.LookupByKey(GetSpellXSpellVisualId(caster, viewer));
if (visual != null)
{
//if (visual.LowViolenceSpellVisualID && forPlayer.GetViolenceLevel() operator 2)
// return visual.LowViolenceSpellVisualID;
return visual.SpellVisualID;
}
return 0;
}
public void _InitializeExplicitTargetMask()
{
bool srcSet = false;
bool dstSet = false;
SpellCastTargetFlags targetMask = Targets;
// prepare target mask using effect target entries
foreach (var effectInfo in GetEffects())
{
if (!effectInfo.IsEffect())
continue;
targetMask |= effectInfo.TargetA.GetExplicitTargetMask(ref srcSet, ref dstSet);
targetMask |= effectInfo.TargetB.GetExplicitTargetMask(ref srcSet, ref dstSet);
// add explicit target flags based on spell effects which have SpellEffectImplicitTargetTypes.Explicit and no valid target provided
if (effectInfo.GetImplicitTargetType() != SpellEffectImplicitTargetTypes.Explicit)
continue;
// extend explicit target mask only if valid targets for effect could not be provided by target types
SpellCastTargetFlags effectTargetMask = effectInfo.GetMissingTargetMask(srcSet, dstSet, targetMask);
// don't add explicit object/dest flags when spell has no max range
if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f)
effectTargetMask &= ~(SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.Gameobject | SpellCastTargetFlags.CorpseMask | SpellCastTargetFlags.DestLocation);
targetMask |= effectTargetMask;
}
ExplicitTargetMask = (uint)targetMask;
}
public bool _isPositiveTarget(SpellEffectInfo effect)
{
if (!effect.IsEffect())
return true;
return effect.TargetA.GetCheckType() != SpellTargetCheckTypes.Enemy &&
effect.TargetB.GetCheckType() != SpellTargetCheckTypes.Enemy;
}
bool _isPositiveEffectImpl(SpellInfo spellInfo, SpellEffectInfo effect, List<Tuple<SpellInfo, uint>> visited)
{
if (!effect.IsEffect())
return true;
// attribute may be already set in DB
if (!spellInfo.IsPositiveEffect(effect.EffectIndex))
return false;
// passive auras like talents are all positive
if (spellInfo.IsPassive())
return true;
// not found a single positive spell with this attribute
if (spellInfo.HasAttribute(SpellAttr0.AuraIsDebuff))
return false;
if (spellInfo.HasAttribute(SpellAttr4.AuraIsBuff))
return true;
if (effect.EffectAttributes.HasFlag(SpellEffectAttributes.IsHarmful))
return false;
visited.Add(Tuple.Create(spellInfo, effect.EffectIndex));
//We need scaling level info for some auras that compute bp 0 or positive but should be debuffs
float bpScalePerLevel = effect.RealPointsPerLevel;
int bp = effect.CalcValue();
switch (spellInfo.SpellFamilyName)
{
case SpellFamilyNames.Generic:
switch (spellInfo.Id)
{
case 40268: // Spiritual Vengeance, Teron Gorefiend, Black Temple
case 61987: // Avenging Wrath Marker
case 61988: // Divine Shield exclude aura
case 64412: // Phase Punch, Algalon the Observer, Ulduar
case 72410: // Rune of Blood, Saurfang, Icecrown Citadel
case 71204: // Touch of Insignificance, Lady Deathwhisper, Icecrown Citadel
return false;
case 24732: // Bat Costume
case 30877: // Tag Murloc
case 61716: // Rabbit Costume
case 61734: // Noblegarden Bunny
case 62344: // Fists of Stone
case 50344: // Dream Funnel
case 61819: // Manabonked! (item)
case 61834: // Manabonked! (minigob)
case 73523: // Rigor Mortis
return true;
default:
break;
}
break;
case SpellFamilyNames.Rogue:
switch (spellInfo.Id)
{
// Envenom must be considered as a positive effect even though it deals damage
case 32645: // Envenom
return true;
case 40251: // Shadow of Death, Teron Gorefiend, Black Temple
return false;
default:
break;
}
break;
case SpellFamilyNames.Warrior:
// Slam, Execute
if ((spellInfo.SpellFamilyFlags[0] & 0x20200000) != 0)
return false;
break;
default:
break;
}
switch (spellInfo.Mechanic)
{
case Mechanics.ImmuneShield:
return true;
default:
break;
}
// Special case: effects which determine positivity of whole spell
if (spellInfo.HasAttribute(SpellAttr1.AuraUnique))
{
// check for targets, there seems to be an assortment of dummy triggering spells that should be negative
foreach (var otherEffect in spellInfo.GetEffects())
if (!_isPositiveTarget(otherEffect))
return false;
}
foreach (var otherEffect in spellInfo.GetEffects())
{
switch (otherEffect.Effect)
{
case SpellEffectName.Heal:
case SpellEffectName.LearnSpell:
case SpellEffectName.SkillStep:
case SpellEffectName.HealPct:
return true;
case SpellEffectName.Instakill:
if (otherEffect.EffectIndex != effect.EffectIndex && // for spells like 38044: instakill effect is negative but auras on target must count as buff
otherEffect.TargetA.GetTarget() == effect.TargetA.GetTarget() &&
otherEffect.TargetB.GetTarget() == effect.TargetB.GetTarget())
return false;
break;
default:
break;
}
if (otherEffect.IsAura())
{
switch (otherEffect.ApplyAuraName)
{
case AuraType.ModStealth:
case AuraType.ModUnattackable:
return true;
case AuraType.SchoolHealAbsorb:
case AuraType.Empathy:
case AuraType.ModSpellDamageFromCaster:
case AuraType.PreventsFleeing:
return false;
default:
break;
}
}
}
switch (effect.Effect)
{
case SpellEffectName.WeaponDamage:
case SpellEffectName.WeaponDamageNoSchool:
case SpellEffectName.NormalizedWeaponDmg:
case SpellEffectName.WeaponPercentDamage:
case SpellEffectName.SchoolDamage:
case SpellEffectName.EnvironmentalDamage:
case SpellEffectName.HealthLeech:
case SpellEffectName.Instakill:
case SpellEffectName.PowerDrain:
case SpellEffectName.StealBeneficialBuff:
case SpellEffectName.InterruptCast:
case SpellEffectName.Pickpocket:
case SpellEffectName.GameObjectDamage:
case SpellEffectName.DurabilityDamage:
case SpellEffectName.DurabilityDamagePct:
case SpellEffectName.ApplyAreaAuraEnemy:
case SpellEffectName.Tamecreature:
case SpellEffectName.Distract:
return false;
case SpellEffectName.Energize:
case SpellEffectName.EnergizePct:
case SpellEffectName.HealPct:
case SpellEffectName.HealMaxHealth:
case SpellEffectName.HealMechanical:
return true;
case SpellEffectName.KnockBack:
case SpellEffectName.Charge:
case SpellEffectName.PersistentAreaAura:
case SpellEffectName.AttackMe:
case SpellEffectName.PowerBurn:
// check targets
if (!_isPositiveTarget(effect))
return false;
break;
case SpellEffectName.Dispel:
// non-positive dispel
switch ((DispelType)effect.MiscValue)
{
case DispelType.Stealth:
case DispelType.Invisibility:
case DispelType.Enrage:
return false;
default:
break;
}
// also check targets
if (!_isPositiveTarget(effect))
return false;
break;
case SpellEffectName.DispelMechanic:
if (!_isPositiveTarget(effect))
{
// non-positive mechanic dispel on negative target
switch ((Mechanics)effect.MiscValue)
{
case Mechanics.Bandage:
case Mechanics.Shield:
case Mechanics.Mount:
case Mechanics.Invulnerability:
return false;
default:
break;
}
}
break;
case SpellEffectName.Threat:
case SpellEffectName.ModifyThreatPercent:
// check targets AND basepoints
if (!_isPositiveTarget(effect) && bp > 0)
return false;
break;
default:
break;
}
if (effect.IsAura())
{
// non-positive aura use
switch (effect.ApplyAuraName)
{
case AuraType.ModStat: // dependent from basepoint sign (negative -> negative)
case AuraType.ModSkill:
case AuraType.ModSkill2:
case AuraType.ModDodgePercent:
case AuraType.ModHealingDone:
case AuraType.ModDamageDoneCreature:
case AuraType.ObsModHealth:
case AuraType.ObsModPower:
case AuraType.ModCritPct:
case AuraType.ModHitChance:
case AuraType.ModSpellHitChance:
case AuraType.ModSpellCritChance:
case AuraType.ModRangedHaste:
case AuraType.ModMeleeRangedHaste:
case AuraType.ModCastingSpeedNotStack:
case AuraType.HasteSpells:
case AuraType.ModRecoveryRateBySpellLabel:
case AuraType.ModDetectRange:
case AuraType.ModIncreaseHealthPercent:
case AuraType.ModTotalStatPercentage:
case AuraType.ModIncreaseSwimSpeed:
case AuraType.ModPercentStat:
case AuraType.ModIncreaseHealth:
case AuraType.ModSpeedAlways:
if (bp < 0 || bpScalePerLevel < 0) //TODO: What if both are 0? Should it be a buff or debuff?
return false;
break;
case AuraType.ModAttackspeed: // some buffs have negative bp, check both target and bp
case AuraType.ModMeleeHaste:
case AuraType.ModDamageDone:
case AuraType.ModResistance:
case AuraType.ModResistancePct:
case AuraType.ModRating:
case AuraType.ModAttackPower:
case AuraType.ModRangedAttackPower:
case AuraType.ModDamagePercentDone:
case AuraType.ModSpeedSlowAll:
case AuraType.MeleeSlow:
case AuraType.ModAttackPowerPct:
case AuraType.ModHealingDonePercent:
case AuraType.ModHealingPct:
if (!_isPositiveTarget(effect) || bp < 0)
return false;
break;
case AuraType.ModDamageTaken: // dependent from basepoint sign (positive . negative)
case AuraType.ModMeleeDamageTaken:
case AuraType.ModMeleeDamageTakenPct:
case AuraType.ModPowerCostSchool:
case AuraType.ModPowerCostSchoolPct:
case AuraType.ModMechanicDamageTakenPercent:
if (bp > 0)
return false;
break;
case AuraType.ModDamagePercentTaken: // check targets and basepoints (ex Recklessness)
if (!_isPositiveTarget(effect) && bp > 0)
return false;
break;
case AuraType.ModHealthRegenPercent: // check targets and basepoints (target enemy and negative bp -> negative)
if (!_isPositiveTarget(effect) && bp < 0)
return false;
break;
case AuraType.AddTargetTrigger:
return true;
case AuraType.PeriodicTriggerSpellWithValue:
case AuraType.PeriodicTriggerSpellFromClient:
SpellInfo spellTriggeredProto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, spellInfo.Difficulty);
if (spellTriggeredProto != null)
{
// negative targets of main spell return early
foreach (var spellTriggeredEffect in spellTriggeredProto.GetEffects())
{
// already seen this
if (visited.Contains(Tuple.Create(spellTriggeredProto, spellTriggeredEffect.EffectIndex)))
continue;
if (!spellTriggeredEffect.IsEffect())
continue;
// if non-positive trigger cast targeted to positive target this main cast is non-positive
// this will place this spell auras as debuffs
if (_isPositiveTarget(spellTriggeredEffect) && !_isPositiveEffectImpl(spellTriggeredProto, spellTriggeredEffect, visited))
return false;
}
}
break;
case AuraType.PeriodicTriggerSpell:
case AuraType.ModStun:
case AuraType.Transform:
case AuraType.ModDecreaseSpeed:
case AuraType.ModFear:
case AuraType.ModTaunt:
// special auras: they may have non negative target but still need to be marked as debuff
// checked again after all effects (SpellInfo::_InitializeSpellPositivity)
case AuraType.ModPacify:
case AuraType.ModPacifySilence:
case AuraType.ModDisarm:
case AuraType.ModDisarmOffhand:
case AuraType.ModDisarmRanged:
case AuraType.ModCharm:
case AuraType.AoeCharm:
case AuraType.ModPossess:
case AuraType.ModLanguage:
case AuraType.DamageShield:
case AuraType.ProcTriggerSpell:
case AuraType.ModAttackerMeleeHitChance:
case AuraType.ModAttackerRangedHitChance:
case AuraType.ModAttackerSpellHitChance:
case AuraType.ModAttackerMeleeCritChance:
case AuraType.ModAttackerSpellAndWeaponCritChance:
case AuraType.Dummy:
case AuraType.PeriodicDummy:
case AuraType.ModHealing:
case AuraType.ModWeaponCritPercent:
case AuraType.PowerBurn:
case AuraType.ModCooldown:
case AuraType.ModChargeCooldown:
case AuraType.ModIncreaseSpeed:
case AuraType.ModParryPercent:
case AuraType.SetVehicleId:
case AuraType.PeriodicEnergize:
case AuraType.EffectImmunity:
case AuraType.OverrideClassScripts:
case AuraType.ModShapeshift:
case AuraType.ModThreat:
case AuraType.ProcTriggerSpellWithValue:
// check target for positive and negative spells
if (!_isPositiveTarget(effect))
return false;
break;
case AuraType.ModConfuse:
case AuraType.ChannelDeathItem:
case AuraType.ModRoot:
case AuraType.ModRoot2:
case AuraType.ModSilence:
case AuraType.ModDetaunt:
case AuraType.Ghost:
case AuraType.ModLeech:
case AuraType.PeriodicManaLeech:
case AuraType.ModStalked:
case AuraType.PreventResurrection:
case AuraType.PeriodicDamage:
case AuraType.PeriodicWeaponPercentDamage:
case AuraType.PeriodicDamagePercent:
case AuraType.MeleeAttackPowerAttackerBonus:
case AuraType.RangedAttackPowerAttackerBonus:
return false;
case AuraType.MechanicImmunity:
{
// non-positive immunities
switch ((Mechanics)effect.MiscValue)
{
case Mechanics.Bandage:
case Mechanics.Shield:
case Mechanics.Mount:
case Mechanics.Invulnerability:
return false;
default:
break;
}
break;
}
case AuraType.AddFlatModifier: // mods
case AuraType.AddPctModifier:
case AuraType.AddFlatModifierBySpellLabel:
case AuraType.AddPctModifierBySpellLabel:
{
switch ((SpellModOp)effect.MiscValue)
{
case SpellModOp.ChangeCastTime: // dependent from basepoint sign (positive . negative)
case SpellModOp.Period:
case SpellModOp.PowerCostOnMiss:
case SpellModOp.StartCooldown:
if (bp > 0)
return false;
break;
case SpellModOp.Cooldown:
case SpellModOp.PowerCost0:
case SpellModOp.PowerCost1:
case SpellModOp.PowerCost2:
if (!spellInfo.IsPositive() && bp > 0) // dependent on prev effects too (ex Arcane Power)
return false;
break;
case SpellModOp.PointsIndex0: // always positive
case SpellModOp.PointsIndex1:
case SpellModOp.PointsIndex2:
case SpellModOp.PointsIndex3:
case SpellModOp.PointsIndex4:
case SpellModOp.Points:
case SpellModOp.Hate:
case SpellModOp.ChainAmplitude:
case SpellModOp.Amplitude:
return true;
case SpellModOp.Duration:
case SpellModOp.CritChance:
case SpellModOp.HealingAndDamage:
case SpellModOp.ChainTargets:
if (!spellInfo.IsPositive() && bp < 0) // dependent on prev effects too
return false;
break;
default: // dependent from basepoint sign (negative . negative)
if (bp < 0)
return false;
break;
}
break;
}
default:
break;
}
}
// negative spell if triggered spell is negative
if (effect.ApplyAuraName == 0 && effect.TriggerSpell != 0)
{
SpellInfo spellTriggeredProto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, spellInfo.Difficulty);
if (spellTriggeredProto != null)
{
// spells with at least one negative effect are considered negative
// some self-applied spells have negative effects but in self casting case negative check ignored.
foreach (var spellTriggeredEffect in spellTriggeredProto.GetEffects())
{
// already seen this
if (visited.Contains(Tuple.Create(spellTriggeredProto, spellTriggeredEffect.EffectIndex)))
continue;
if (!spellTriggeredEffect.IsEffect())
continue;
if (!_isPositiveEffectImpl(spellTriggeredProto, spellTriggeredEffect, visited))
return false;
}
}
}
// ok, positive
return true;
}
public void InitializeSpellPositivity()
{
List<Tuple<SpellInfo, uint>> visited = new();
foreach (SpellEffectInfo effect in GetEffects())
if (!_isPositiveEffectImpl(this, effect, visited))
NegativeEffects[(int)effect.EffectIndex] = true;
// additional checks after effects marked
foreach (var spellEffectInfo in GetEffects())
{
if (!spellEffectInfo.IsEffect() || !IsPositiveEffect(spellEffectInfo.EffectIndex))
continue;
switch (spellEffectInfo.ApplyAuraName)
{
// has other non positive effect?
// then it should be marked negative if has same target as negative effect (ex 8510, 8511, 8893, 10267)
case AuraType.Dummy:
case AuraType.ModStun:
case AuraType.ModFear:
case AuraType.ModTaunt:
case AuraType.Transform:
case AuraType.ModAttackspeed:
case AuraType.ModDecreaseSpeed:
{
for (uint j = spellEffectInfo.EffectIndex + 1; j < GetEffects().Count; ++j)
if (!IsPositiveEffect(j)
&& spellEffectInfo.TargetA.GetTarget() == GetEffect(j).TargetA.GetTarget()
&& spellEffectInfo.TargetB.GetTarget() == GetEffect(j).TargetB.GetTarget())
NegativeEffects[(int)spellEffectInfo.EffectIndex] = true;
break;
}
default:
break;
}
}
}
public void _UnloadImplicitTargetConditionLists()
{
// find the same instances of ConditionList and delete them.
foreach (SpellEffectInfo effect in _effects)
effect.ImplicitTargetConditions = null;
}
public bool MeetsFutureSpellPlayerCondition(Player player)
{
if (ShowFutureSpellPlayerConditionID == 0)
return false;
return ConditionManager.IsPlayerMeetingCondition(player, ShowFutureSpellPlayerConditionID);
}
public bool HasLabel(uint labelId)
{
return Labels.Contains(labelId);
}
public static SpellCastTargetFlags GetTargetFlagMask(SpellTargetObjectTypes objType)
{
switch (objType)
{
case SpellTargetObjectTypes.Dest:
return SpellCastTargetFlags.DestLocation;
case SpellTargetObjectTypes.UnitAndDest:
return SpellCastTargetFlags.DestLocation | SpellCastTargetFlags.Unit;
case SpellTargetObjectTypes.CorpseAlly:
return SpellCastTargetFlags.CorpseAlly;
case SpellTargetObjectTypes.CorpseEnemy:
return SpellCastTargetFlags.CorpseEnemy;
case SpellTargetObjectTypes.Corpse:
return SpellCastTargetFlags.CorpseAlly | SpellCastTargetFlags.CorpseEnemy;
case SpellTargetObjectTypes.Unit:
return SpellCastTargetFlags.Unit;
case SpellTargetObjectTypes.Gobj:
return SpellCastTargetFlags.Gameobject;
case SpellTargetObjectTypes.GobjItem:
return SpellCastTargetFlags.GameobjectItem;
case SpellTargetObjectTypes.Item:
return SpellCastTargetFlags.Item;
case SpellTargetObjectTypes.Src:
return SpellCastTargetFlags.SourceLocation;
default:
return SpellCastTargetFlags.None;
}
}
public uint GetCategory()
{
return CategoryId;
}
public List<SpellEffectInfo> GetEffects() { return _effects; }
public SpellEffectInfo GetEffect(uint index) { return _effects[(int)index]; }
public bool HasTargetType(Targets target)
{
foreach (var effectInfo in _effects)
if (effectInfo.TargetA.GetTarget() == target || effectInfo.TargetB.GetTarget() == target)
return true;
return false;
}
public List<SpellXSpellVisualRecord> GetSpellVisuals()
{
return _visuals;
}
public bool HasAttribute(SpellAttr0 attribute) { return Convert.ToBoolean(Attributes & attribute); }
public bool HasAttribute(SpellAttr1 attribute) { return Convert.ToBoolean(AttributesEx & attribute); }
public bool HasAttribute(SpellAttr2 attribute) { return Convert.ToBoolean(AttributesEx2 & attribute); }
public bool HasAttribute(SpellAttr3 attribute) { return Convert.ToBoolean(AttributesEx3 & attribute); }
public bool HasAttribute(SpellAttr4 attribute) { return Convert.ToBoolean(AttributesEx4 & attribute); }
public bool HasAttribute(SpellAttr5 attribute) { return Convert.ToBoolean(AttributesEx5 & attribute); }
public bool HasAttribute(SpellAttr6 attribute) { return Convert.ToBoolean(AttributesEx6 & attribute); }
public bool HasAttribute(SpellAttr7 attribute) { return Convert.ToBoolean(AttributesEx7 & attribute); }
public bool HasAttribute(SpellAttr8 attribute) { return Convert.ToBoolean(AttributesEx8 & attribute); }
public bool HasAttribute(SpellAttr9 attribute) { return Convert.ToBoolean(AttributesEx9 & attribute); }
public bool HasAttribute(SpellAttr10 attribute) { return Convert.ToBoolean(AttributesEx10 & attribute); }
public bool HasAttribute(SpellAttr11 attribute) { return Convert.ToBoolean(AttributesEx11 & attribute); }
public bool HasAttribute(SpellAttr12 attribute) { return Convert.ToBoolean(AttributesEx12 & attribute); }
public bool HasAttribute(SpellAttr13 attribute) { return Convert.ToBoolean(AttributesEx13 & attribute); }
public bool HasAttribute(SpellAttr14 attribute) { return Convert.ToBoolean(AttributesEx14 & attribute); }
public bool HasAttribute(SpellCustomAttributes attribute) { return Convert.ToBoolean(AttributesCu & attribute); }
public bool CanBeInterrupted(WorldObject interruptCaster, Unit interruptTarget, bool ignoreImmunity = false)
{
return HasAttribute(SpellAttr7.NoUiNotInterruptible)
|| HasChannelInterruptFlag(SpellAuraInterruptFlags.Damage | SpellAuraInterruptFlags.EnteringCombat)
|| (interruptTarget.IsPlayer() && InterruptFlags.HasFlag(SpellInterruptFlags.DamageCancelsPlayerOnly))
|| InterruptFlags.HasFlag(SpellInterruptFlags.DamageCancels)
|| (interruptCaster != null && interruptCaster.IsUnit() && interruptCaster.ToUnit().HasAuraTypeWithMiscvalue(AuraType.AllowInterruptSpell, (int)Id))
|| (((interruptTarget.GetMechanicImmunityMask() & (1 << (int)Mechanics.Interrupt)) == 0 || ignoreImmunity)
&& !interruptTarget.HasAuraTypeWithAffectMask(AuraType.PreventInterrupt, this)
&& PreventionType.HasAnyFlag(SpellPreventionType.Silence));
}
public bool HasAnyAuraInterruptFlag() { return AuraInterruptFlags != SpellAuraInterruptFlags.None || AuraInterruptFlags2 != SpellAuraInterruptFlags2.None; }
public bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) { return AuraInterruptFlags.HasAnyFlag(flag); }
public bool HasAuraInterruptFlag(SpellAuraInterruptFlags2 flag) { return AuraInterruptFlags2.HasAnyFlag(flag); }
public bool HasChannelInterruptFlag(SpellAuraInterruptFlags flag) { return ChannelInterruptFlags.HasAnyFlag(flag); }
public bool HasChannelInterruptFlag(SpellAuraInterruptFlags2 flag) { return ChannelInterruptFlags2.HasAnyFlag(flag); }
#region Fields
public uint Id { get; set; }
public Difficulty Difficulty { get; set; }
public uint CategoryId { get; set; }
public DispelType Dispel { get; set; }
public Mechanics Mechanic { get; set; }
public SpellAttr0 Attributes { get; set; }
public SpellAttr1 AttributesEx { get; set; }
public SpellAttr2 AttributesEx2 { get; set; }
public SpellAttr3 AttributesEx3 { get; set; }
public SpellAttr4 AttributesEx4 { get; set; }
public SpellAttr5 AttributesEx5 { get; set; }
public SpellAttr6 AttributesEx6 { get; set; }
public SpellAttr7 AttributesEx7 { get; set; }
public SpellAttr8 AttributesEx8 { get; set; }
public SpellAttr9 AttributesEx9 { get; set; }
public SpellAttr10 AttributesEx10 { get; set; }
public SpellAttr11 AttributesEx11 { get; set; }
public SpellAttr12 AttributesEx12 { get; set; }
public SpellAttr13 AttributesEx13 { get; set; }
public SpellAttr14 AttributesEx14 { get; set; }
public SpellCustomAttributes AttributesCu { get; set; }
public BitSet NegativeEffects { get; set; } = new BitSet(SpellConst.MaxEffects);
public ulong Stances { get; set; }
public ulong StancesNot { get; set; }
public SpellCastTargetFlags Targets { get; set; }
public uint TargetCreatureType { get; set; }
public uint RequiresSpellFocus { get; set; }
public uint FacingCasterFlags { get; set; }
public AuraStateType CasterAuraState { get; set; }
public AuraStateType TargetAuraState { get; set; }
public AuraStateType ExcludeCasterAuraState { get; set; }
public AuraStateType ExcludeTargetAuraState { get; set; }
public uint CasterAuraSpell { get; set; }
public uint TargetAuraSpell { get; set; }
public uint ExcludeCasterAuraSpell { get; set; }
public uint ExcludeTargetAuraSpell { get; set; }
public AuraType CasterAuraType { get; set; }
public AuraType TargetAuraType { get; set; }
public AuraType ExcludeCasterAuraType { get; set; }
public AuraType ExcludeTargetAuraType { get; set; }
public SpellCastTimesRecord CastTimeEntry { get; set; }
public uint RecoveryTime { get; set; }
public uint CategoryRecoveryTime { get; set; }
public uint StartRecoveryCategory { get; set; }
public uint StartRecoveryTime { get; set; }
public uint CooldownAuraSpellId { get; set; }
public SpellInterruptFlags InterruptFlags { get; set; }
public SpellAuraInterruptFlags AuraInterruptFlags { get; set; }
public SpellAuraInterruptFlags2 AuraInterruptFlags2 { get; set; }
public SpellAuraInterruptFlags ChannelInterruptFlags { get; set; }
public SpellAuraInterruptFlags2 ChannelInterruptFlags2 { get; set; }
public ProcFlagsInit ProcFlags { get; set; }
public uint ProcChance { get; set; }
public uint ProcCharges { get; set; }
public uint ProcCooldown { get; set; }
public float ProcBasePPM { get; set; }
List<SpellProcsPerMinuteModRecord> ProcPPMMods = new();
public uint MaxLevel { get; set; }
public uint BaseLevel { get; set; }
public uint SpellLevel { get; set; }
public SpellDurationRecord DurationEntry { get; set; }
public SpellPowerRecord[] PowerCosts = new SpellPowerRecord[SpellConst.MaxPowersPerSpell];
public SpellRangeRecord RangeEntry { get; set; }
public float Speed { get; set; }
public float LaunchDelay { get; set; }
public uint StackAmount { get; set; }
public uint[] Totem = new uint[SpellConst.MaxTotems];
public uint[] TotemCategory = new uint[SpellConst.MaxTotems];
public int[] Reagent = new int[SpellConst.MaxReagents];
public uint[] ReagentCount = new uint[SpellConst.MaxReagents];
public List<SpellReagentsCurrencyRecord> ReagentsCurrency = new();
public ItemClass EquippedItemClass { get; set; }
public int EquippedItemSubClassMask { get; set; }
public int EquippedItemInventoryTypeMask { get; set; }
public uint IconFileDataId { get; set; }
public uint ActiveIconFileDataId { get; set; }
public uint ContentTuningId { get; set; }
public uint ShowFutureSpellPlayerConditionID { get; set; }
public LocalizedString SpellName { get; set; }
public float ConeAngle { get; set; }
public float Width { get; set; }
public uint MaxTargetLevel { get; set; }
public uint MaxAffectedTargets { get; set; }
public SpellFamilyNames SpellFamilyName { get; set; }
public FlagArray128 SpellFamilyFlags { get; set; }
public SpellDmgClass DmgClass { get; set; }
public SpellPreventionType PreventionType { get; set; }
public int RequiredAreasID { get; set; }
public SpellSchoolMask SchoolMask { get; set; }
public uint ChargeCategoryId;
public List<uint> Labels = new();
public List<TimeSpan> EmpowerStageThresholds = new();
// SpellScalingEntry
public ScalingInfo Scaling;
public uint ExplicitTargetMask { get; set; }
public SpellChainNode ChainEntry { get; set; }
public SqrtDamageAndHealingDiminishingStruct SqrtDamageAndHealingDiminishing;
List<SpellEffectInfo> _effects = new();
List<SpellXSpellVisualRecord> _visuals = new();
SpellSpecificType _spellSpecific;
AuraStateType _auraState;
SpellDiminishInfo _diminishInfo;
ulong _allowedMechanicMask;
#endregion
public struct ScalingInfo
{
public uint MinScalingLevel;
public uint MaxScalingLevel;
public uint ScalesFromItemLevel;
}
public struct SqrtDamageAndHealingDiminishingStruct
{
public int MaxTargets; // The amount of targets after the damage decreases by the Square Root AOE formula
public int NumNonDiminishedTargets; // The amount of targets that still take the full amount before the damage decreases by the Square Root AOE formula
}
}
public class SpellEffectInfo
{
public SpellEffectInfo(SpellInfo spellInfo, SpellEffectRecord effect = null)
{
_spellInfo = spellInfo;
if (effect != null)
{
EffectIndex = (uint)effect.EffectIndex;
Effect = (SpellEffectName)effect.Effect;
ApplyAuraName = (AuraType)effect.EffectAura;
ApplyAuraPeriod = effect.EffectAuraPeriod;
BasePoints = (int)effect.EffectBasePoints;
RealPointsPerLevel = effect.EffectRealPointsPerLevel;
PointsPerResource = effect.EffectPointsPerResource;
Amplitude = effect.EffectAmplitude;
ChainAmplitude = effect.EffectChainAmplitude;
BonusCoefficient = effect.EffectBonusCoefficient;
MiscValue = effect.EffectMiscValue[0];
MiscValueB = effect.EffectMiscValue[1];
Mechanic = (Mechanics)effect.EffectMechanic;
PositionFacing = effect.EffectPosFacing;
TargetA = new SpellImplicitTargetInfo((Targets)effect.ImplicitTarget[0]);
TargetB = new SpellImplicitTargetInfo((Targets)effect.ImplicitTarget[1]);
TargetARadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(effect.EffectRadiusIndex[0]);
TargetBRadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(effect.EffectRadiusIndex[1]);
ChainTargets = effect.EffectChainTargets;
ItemType = effect.EffectItemType;
TriggerSpell = effect.EffectTriggerSpell;
SpellClassMask = effect.EffectSpellClassMask;
BonusCoefficientFromAP = effect.BonusCoefficientFromAP;
Scaling.Class = effect.ScalingClass;
Scaling.Coefficient = effect.Coefficient;
Scaling.Variance = effect.Variance;
Scaling.ResourceCoefficient = effect.ResourceCoefficient;
EffectAttributes = effect.EffectAttributes;
}
ImplicitTargetConditions = null;
_immunityInfo = new ImmunityInfo();
}
public bool IsEffect()
{
return Effect != 0;
}
public bool IsEffect(SpellEffectName effectName)
{
return Effect == effectName;
}
public bool IsAura()
{
return (IsUnitOwnedAuraEffect() || Effect == SpellEffectName.PersistentAreaAura) && ApplyAuraName != 0;
}
public bool IsAura(AuraType aura)
{
return IsAura() && ApplyAuraName == aura;
}
public bool IsTargetingArea()
{
return TargetA.IsArea() || TargetB.IsArea();
}
public bool IsAreaAuraEffect()
{
if (Effect == SpellEffectName.ApplyAreaAuraParty ||
Effect == SpellEffectName.ApplyAreaAuraRaid ||
Effect == SpellEffectName.ApplyAreaAuraFriend ||
Effect == SpellEffectName.ApplyAreaAuraEnemy ||
Effect == SpellEffectName.ApplyAreaAuraPet ||
Effect == SpellEffectName.ApplyAreaAuraOwner ||
Effect == SpellEffectName.ApplyAreaAuraSummons ||
Effect == SpellEffectName.ApplyAreaAuraPartyNonrandom)
return true;
return false;
}
public bool IsUnitOwnedAuraEffect()
{
return IsAreaAuraEffect() || Effect == SpellEffectName.ApplyAura || Effect == SpellEffectName.ApplyAuraOnPet;
}
public int CalcValue(WorldObject caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
{
return CalcValue(out _, caster, bp, target, castItemId, itemLevel);
}
public int CalcValue(out float variance, WorldObject caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1)
{
variance = 0.0f;
double basePointsPerLevel = RealPointsPerLevel;
// TODO: this needs to be a float, not rounded
int basePoints = CalcBaseValue(caster, target, castItemId, itemLevel);
double value = bp.HasValue ? bp.Value : basePoints;
double comboDamage = PointsPerResource;
Unit casterUnit = null;
if (caster != null)
casterUnit = caster.ToUnit();
if (Scaling.Variance != 0)
{
float delta = Math.Abs(Scaling.Variance * 0.5f);
double valueVariance = RandomHelper.FRand(-delta, delta);
value += (double)basePoints * valueVariance;
variance = (float)valueVariance;
}
// base amount modification based on spell lvl vs caster lvl
if (Scaling.Coefficient != 0.0f)
{
if (Scaling.ResourceCoefficient != 0)
comboDamage = Scaling.ResourceCoefficient * value;
}
else if (GetScalingExpectedStat() == ExpectedStatType.None)
{
if (casterUnit != null && basePointsPerLevel != 0.0f)
{
int level = (int)casterUnit.GetLevel();
if (level > (int)_spellInfo.MaxLevel && _spellInfo.MaxLevel > 0)
level = (int)_spellInfo.MaxLevel;
// if base level is greater than spell level, reduce by base level (eg. pilgrims foods)
level -= (int)Math.Max(_spellInfo.BaseLevel, _spellInfo.SpellLevel);
if (level < 0)
level = 0;
value += level * basePointsPerLevel;
}
}
// random damage
if (casterUnit != null)
{
// bonus amount from combo points
if (comboDamage != 0)
{
int comboPoints = casterUnit.GetPower(PowerType.ComboPoints);
if (comboPoints != 0)
value += comboDamage * comboPoints;
}
if (caster != null)
value = caster.ApplyEffectModifiers(_spellInfo, EffectIndex, value);
}
return (int)Math.Round(value);
}
public int CalcBaseValue(WorldObject caster, Unit target, uint itemId, int itemLevel)
{
if (Scaling.Coefficient != 0.0f)
{
uint level = _spellInfo.SpellLevel;
if (target != null && _spellInfo.HasAttribute(SpellAttr8.UseTargetsLevelForSpellScaling))
level = target.GetLevel();
else if (caster != null && caster.IsUnit())
level = caster.ToUnit().GetLevel();
if (_spellInfo.BaseLevel != 0 && !_spellInfo.HasAttribute(SpellAttr11.ScalesWithItemLevel) && _spellInfo.HasAttribute(SpellAttr10.UseSpellBaseLevelForScaling))
level = _spellInfo.BaseLevel;
if (_spellInfo.Scaling.MinScalingLevel != 0 && _spellInfo.Scaling.MinScalingLevel > level)
level = _spellInfo.Scaling.MinScalingLevel;
if (_spellInfo.Scaling.MaxScalingLevel != 0 && _spellInfo.Scaling.MaxScalingLevel < level)
level = _spellInfo.Scaling.MaxScalingLevel;
float tempValue = 0.0f;
if (level > 0)
{
if (Scaling.Class == 0)
return 0;
uint effectiveItemLevel = itemLevel != -1 ? (uint)itemLevel : 1u;
if (_spellInfo.Scaling.ScalesFromItemLevel != 0 || _spellInfo.HasAttribute(SpellAttr11.ScalesWithItemLevel))
{
if (_spellInfo.Scaling.ScalesFromItemLevel != 0)
effectiveItemLevel = _spellInfo.Scaling.ScalesFromItemLevel;
if (Scaling.Class == -8 || Scaling.Class == -9)
{
RandPropPointsRecord randPropPoints = CliDB.RandPropPointsStorage.LookupByKey(effectiveItemLevel);
if (randPropPoints == null)
randPropPoints = CliDB.RandPropPointsStorage.LookupByKey(CliDB.RandPropPointsStorage.GetNumRows() - 1);
tempValue = Scaling.Class == -8 ? randPropPoints.DamageReplaceStatF : randPropPoints.DamageSecondaryF;
}
else
tempValue = ItemEnchantmentManager.GetRandomPropertyPoints(effectiveItemLevel, ItemQuality.Rare, InventoryType.Chest, 0);
}
else
tempValue = CliDB.GetSpellScalingColumnForClass(CliDB.SpellScalingGameTable.GetRow(level), Scaling.Class);
if (Scaling.Class == -7)
{
GtGenericMultByILvlRecord ratingMult = CliDB.CombatRatingsMultByILvlGameTable.GetRow(effectiveItemLevel);
if (ratingMult != null)
{
ItemSparseRecord itemSparse = CliDB.ItemSparseStorage.LookupByKey(itemId);
if (itemSparse != null)
tempValue *= CliDB.GetIlvlStatMultiplier(ratingMult, itemSparse.inventoryType);
}
}
if (Scaling.Class == -6)
{
GtGenericMultByILvlRecord staminaMult = CliDB.StaminaMultByILvlGameTable.GetRow(effectiveItemLevel);
if (staminaMult != null)
{
ItemSparseRecord itemSparse = CliDB.ItemSparseStorage.LookupByKey(itemId);
if (itemSparse != null)
tempValue *= CliDB.GetIlvlStatMultiplier(staminaMult, itemSparse.inventoryType);
}
}
}
tempValue *= Scaling.Coefficient;
if (tempValue > 0.0f && tempValue < 1.0f)
tempValue = 1.0f;
return (int)Math.Round(tempValue);
}
else
{
float tempValue = BasePoints;
ExpectedStatType stat = GetScalingExpectedStat();
if (stat != ExpectedStatType.None)
{
if (_spellInfo.HasAttribute(SpellAttr0.ScalesWithCreatureLevel))
stat = ExpectedStatType.CreatureAutoAttackDps;
// TODO - add expansion and content tuning id args?
uint contentTuningId = _spellInfo.ContentTuningId; // content tuning should be passed as arg, the one stored in SpellInfo is fallback
int expansion = -2;
ContentTuningRecord contentTuning = CliDB.ContentTuningStorage.LookupByKey(contentTuningId);
if (contentTuning != null)
expansion = contentTuning.ExpansionID;
uint level = 1;
if (target != null && _spellInfo.HasAttribute(SpellAttr8.UseTargetsLevelForSpellScaling))
level = target.GetLevel();
else if (caster != null && caster.IsUnit())
level = caster.ToUnit().GetLevel();
tempValue = Global.DB2Mgr.EvaluateExpectedStat(stat, level, expansion, 0, Class.None, 0) * BasePoints / 100.0f;
}
return (int)Math.Round(tempValue);
}
}
public float CalcValueMultiplier(WorldObject caster, Spell spell = null)
{
float multiplier = Amplitude;
Player modOwner = (caster != null ? caster.GetSpellModOwner() : null);
if (modOwner != null)
modOwner.ApplySpellMod(_spellInfo, SpellModOp.Amplitude, ref multiplier, spell);
return multiplier;
}
public float CalcDamageMultiplier(WorldObject caster, Spell spell = null)
{
float multiplierPercent = ChainAmplitude * 100.0f;
Player modOwner = (caster != null ? caster.GetSpellModOwner() : null);
if (modOwner != null)
modOwner.ApplySpellMod(_spellInfo, SpellModOp.ChainAmplitude, ref multiplierPercent, spell);
return multiplierPercent / 100.0f;
}
public bool HasRadius(SpellTargetIndex targetIndex)
{
switch (targetIndex)
{
case SpellTargetIndex.TargetA:
return TargetARadiusEntry != null;
case SpellTargetIndex.TargetB:
return TargetBRadiusEntry != null;
default:
return false;
}
}
public float CalcRadius(WorldObject caster = null, SpellTargetIndex targetIndex = SpellTargetIndex.TargetA, Spell spell = null)
{
// TargetA -> TargetARadiusEntry
// TargetB -> TargetBRadiusEntry
// Aura effects have TargetARadiusEntry == TargetBRadiusEntry (mostly)
SpellImplicitTargetInfo target = TargetA;
var entry = TargetARadiusEntry;
if (targetIndex == SpellTargetIndex.TargetB && HasRadius(targetIndex))
{
target = TargetB;
entry = TargetBRadiusEntry;
}
if (entry == null)
return 0.0f;
float radius = entry.RadiusMin;
// Random targets use random value between RadiusMin and RadiusMax
// For other cases, client uses RadiusMax if RadiusMin is 0
if (target.GetTarget() == Targets.DestCasterRandom ||
target.GetTarget() == Targets.DestTargetRandom ||
target.GetTarget() == Targets.DestDestRandom)
radius += (entry.RadiusMax - radius) * RandomHelper.NextSingle();
else if (radius == 0.0f)
radius = entry.RadiusMax;
if (caster != null)
{
Unit casterUnit = caster.ToUnit();
if (casterUnit != null)
radius += entry.RadiusPerLevel * casterUnit.GetLevel();
radius = Math.Min(radius, entry.RadiusMax);
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(_spellInfo, SpellModOp.Radius, ref radius, spell);
}
return radius;
}
public SpellCastTargetFlags GetProvidedTargetMask()
{
return SpellInfo.GetTargetFlagMask(TargetA.GetObjectType()) | SpellInfo.GetTargetFlagMask(TargetB.GetObjectType());
}
public SpellCastTargetFlags GetMissingTargetMask(bool srcSet = false, bool dstSet = false, SpellCastTargetFlags mask = 0)
{
var effImplicitTargetMask = SpellInfo.GetTargetFlagMask(GetUsedTargetObjectType());
SpellCastTargetFlags providedTargetMask = GetProvidedTargetMask() | mask;
// remove all flags covered by effect target mask
if (Convert.ToBoolean(providedTargetMask & SpellCastTargetFlags.UnitMask))
effImplicitTargetMask &= ~SpellCastTargetFlags.UnitMask;
if (Convert.ToBoolean(providedTargetMask & SpellCastTargetFlags.CorpseMask))
effImplicitTargetMask &= ~(SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.CorpseMask);
if (Convert.ToBoolean(providedTargetMask & SpellCastTargetFlags.GameobjectItem))
effImplicitTargetMask &= ~(SpellCastTargetFlags.GameobjectItem | SpellCastTargetFlags.Gameobject | SpellCastTargetFlags.Item);
if (Convert.ToBoolean(providedTargetMask & SpellCastTargetFlags.Gameobject))
effImplicitTargetMask &= ~(SpellCastTargetFlags.Gameobject | SpellCastTargetFlags.GameobjectItem);
if (Convert.ToBoolean(providedTargetMask & SpellCastTargetFlags.Item))
effImplicitTargetMask &= ~(SpellCastTargetFlags.Item | SpellCastTargetFlags.GameobjectItem);
if (dstSet || Convert.ToBoolean(providedTargetMask & SpellCastTargetFlags.DestLocation))
effImplicitTargetMask &= ~SpellCastTargetFlags.DestLocation;
if (srcSet || Convert.ToBoolean(providedTargetMask & SpellCastTargetFlags.SourceLocation))
effImplicitTargetMask &= ~SpellCastTargetFlags.SourceLocation;
return effImplicitTargetMask;
}
public SpellEffectImplicitTargetTypes GetImplicitTargetType()
{
return _data[(int)Effect].ImplicitTargetType;
}
public SpellTargetObjectTypes GetUsedTargetObjectType()
{
return _data[(int)Effect].UsedTargetObjectType;
}
ExpectedStatType GetScalingExpectedStat()
{
switch (Effect)
{
case SpellEffectName.SchoolDamage:
case SpellEffectName.EnvironmentalDamage:
case SpellEffectName.HealthLeech:
case SpellEffectName.WeaponDamageNoSchool:
case SpellEffectName.WeaponDamage:
return ExpectedStatType.CreatureSpellDamage;
case SpellEffectName.Heal:
case SpellEffectName.HealMechanical:
return ExpectedStatType.PlayerHealth;
case SpellEffectName.Energize:
case SpellEffectName.PowerBurn:
if (MiscValue == (int)PowerType.Mana)
return ExpectedStatType.PlayerMana;
return ExpectedStatType.None;
case SpellEffectName.PowerDrain:
return ExpectedStatType.PlayerMana;
case SpellEffectName.ApplyAura:
case SpellEffectName.PersistentAreaAura:
case SpellEffectName.ApplyAreaAuraParty:
case SpellEffectName.ApplyAreaAuraRaid:
case SpellEffectName.ApplyAreaAuraPet:
case SpellEffectName.ApplyAreaAuraFriend:
case SpellEffectName.ApplyAreaAuraEnemy:
case SpellEffectName.ApplyAreaAuraOwner:
case SpellEffectName.ApplyAuraOnPet:
case SpellEffectName.ApplyAreaAuraSummons:
case SpellEffectName.ApplyAreaAuraPartyNonrandom:
switch (ApplyAuraName)
{
case AuraType.PeriodicDamage:
case AuraType.ModDamageDone:
case AuraType.DamageShield:
case AuraType.ProcTriggerDamage:
case AuraType.PeriodicLeech:
case AuraType.ModDamageDoneCreature:
case AuraType.PeriodicHealthFunnel:
case AuraType.ModMeleeAttackPowerVersus:
case AuraType.ModRangedAttackPowerVersus:
case AuraType.ModFlatSpellDamageVersus:
return ExpectedStatType.CreatureSpellDamage;
case AuraType.PeriodicHeal:
case AuraType.ModDamageTaken:
case AuraType.ModIncreaseHealth:
case AuraType.SchoolAbsorb:
case AuraType.ModRegen:
case AuraType.ManaShield:
case AuraType.ModHealing:
case AuraType.ModHealingDone:
case AuraType.ModHealthRegenInCombat:
case AuraType.ModMaxHealth:
case AuraType.ModIncreaseHealth2:
case AuraType.SchoolHealAbsorb:
return ExpectedStatType.PlayerHealth;
case AuraType.PeriodicManaLeech:
return ExpectedStatType.PlayerMana;
case AuraType.ModStat:
case AuraType.ModAttackPower:
case AuraType.ModRangedAttackPower:
return ExpectedStatType.PlayerPrimaryStat;
case AuraType.ModRating:
return ExpectedStatType.PlayerSecondaryStat;
case AuraType.ModResistance:
case AuraType.ModBaseResistance:
case AuraType.ModTargetResistance:
case AuraType.ModBonusArmor:
return ExpectedStatType.ArmorConstant;
case AuraType.PeriodicEnergize:
case AuraType.ModIncreaseEnergy:
case AuraType.ModPowerCostSchool:
case AuraType.ModPowerRegen:
case AuraType.PowerBurn:
case AuraType.ModMaxPower:
if (MiscValue == (int)PowerType.Mana)
return ExpectedStatType.PlayerMana;
return ExpectedStatType.None;
default:
break;
}
break;
default:
break;
}
return ExpectedStatType.None;
}
public ImmunityInfo GetImmunityInfo() { return _immunityInfo; }
public class StaticData
{
public StaticData(SpellEffectImplicitTargetTypes implicittarget, SpellTargetObjectTypes usedtarget)
{
ImplicitTargetType = implicittarget;
UsedTargetObjectType = usedtarget;
}
public SpellEffectImplicitTargetTypes ImplicitTargetType; // defines what target can be added to effect target list if there's no valid target type provided for effect
public SpellTargetObjectTypes UsedTargetObjectType; // defines valid target object type for spell effect
}
static StaticData[] _data = new StaticData[(int)SpellEffectName.TotalSpellEffects]
{
// implicit target type used target object type
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 0
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 1 SPELL_EFFECT_INSTAKILL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 2 SPELL_EFFECT_SCHOOL_DAMAGE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 3 SPELL_EFFECT_DUMMY
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 4 SPELL_EFFECT_PORTAL_TELEPORT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 5 SPELL_EFFECT_5
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 6 SPELL_EFFECT_APPLY_AURA
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 8 SPELL_EFFECT_POWER_DRAIN
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 9 SPELL_EFFECT_HEALTH_LEECH
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 10 SPELL_EFFECT_HEAL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 11 SPELL_EFFECT_BIND
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 12 SPELL_EFFECT_PORTAL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 13 SPELL_EFFECT_TELEPORT_TO_RETURN_POINT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 14 SPELL_EFFECT_INCREASE_CURRENCY_CAP
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 15 SPELL_EFFECT_TELEPORT_WITH_SPELL_VISUAL_KIT_LOADING_SCREEN
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 16 SPELL_EFFECT_QUEST_COMPLETE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.CorpseAlly), // 18 SPELL_EFFECT_RESURRECT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 20 SPELL_EFFECT_DODGE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 21 SPELL_EFFECT_EVADE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 22 SPELL_EFFECT_PARRY
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 23 SPELL_EFFECT_BLOCK
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 24 SPELL_EFFECT_CREATE_ITEM
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 25 SPELL_EFFECT_WEAPON
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 26 SPELL_EFFECT_DEFENSE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 28 SPELL_EFFECT_SUMMON
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 29 SPELL_EFFECT_LEAP
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 30 SPELL_EFFECT_ENERGIZE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 32 SPELL_EFFECT_TRIGGER_MISSILE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.GobjItem), // 33 SPELL_EFFECT_OPEN_LOCK
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 36 SPELL_EFFECT_LEARN_SPELL
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 37 SPELL_EFFECT_SPELL_DEFENSE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 38 SPELL_EFFECT_DISPEL
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 39 SPELL_EFFECT_LANGUAGE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 40 SPELL_EFFECT_DUAL_WIELD
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 41 SPELL_EFFECT_JUMP
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 42 SPELL_EFFECT_JUMP_DEST
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 44 SPELL_EFFECT_SKILL_STEP
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 45 SPELL_EFFECT_ADD_HONOR
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 46 SPELL_EFFECT_SPAWN
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 47 SPELL_EFFECT_TRADE_SKILL
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 48 SPELL_EFFECT_STEALTH
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 49 SPELL_EFFECT_DETECT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 50 SPELL_EFFECT_TRANS_DOOR
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 52 SPELL_EFFECT_SET_MAX_BATTLE_PET_COUNT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 53 SPELL_EFFECT_ENCHANT_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 55 SPELL_EFFECT_TAMECREATURE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 56 SPELL_EFFECT_SUMMON_PET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 57 SPELL_EFFECT_LEARN_PET_SPELL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 58 SPELL_EFFECT_WEAPON_DAMAGE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 60 SPELL_EFFECT_PROFICIENCY
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 61 SPELL_EFFECT_SEND_EVENT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 62 SPELL_EFFECT_POWER_BURN
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 63 SPELL_EFFECT_THREAT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 64 SPELL_EFFECT_TRIGGER_SPELL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 66 SPELL_EFFECT_RECHARGE_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 68 SPELL_EFFECT_INTERRUPT_CAST
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 69 SPELL_EFFECT_DISTRACT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 70 SPELL_EFFECT_COMPLETE_AND_REWARD_WORLD_QUEST
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 71 SPELL_EFFECT_PICKPOCKET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 72 SPELL_EFFECT_ADD_FARSIGHT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 73 SPELL_EFFECT_UNTRAIN_TALENTS
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 74 SPELL_EFFECT_APPLY_GLYPH
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 75 SPELL_EFFECT_HEAL_MECHANICAL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 77 SPELL_EFFECT_SCRIPT_EFFECT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 78 SPELL_EFFECT_ATTACK
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 79 SPELL_EFFECT_SANCTUARY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 80 SPELL_EFFECT_MODIFY_FOLLOWER_ITEM_LEVEL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 81 SPELL_EFFECT_PUSH_ABILITY_TO_ACTION_BAR
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 82 SPELL_EFFECT_BIND_SIGHT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 83 SPELL_EFFECT_DUEL
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 84 SPELL_EFFECT_STUCK
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 85 SPELL_EFFECT_SUMMON_PLAYER
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Gobj), // 86 SPELL_EFFECT_ACTIVATE_OBJECT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Gobj), // 87 SPELL_EFFECT_GAMEOBJECT_DAMAGE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Gobj), // 88 SPELL_EFFECT_GAMEOBJECT_REPAIR
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Gobj), // 89 SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 90 SPELL_EFFECT_KILL_CREDIT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 91 SPELL_EFFECT_THREAT_ALL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 93 SPELL_EFFECT_FORCE_DESELECT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 94 SPELL_EFFECT_SELF_RESURRECT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 95 SPELL_EFFECT_SKINNING
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 96 SPELL_EFFECT_CHARGE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 97 SPELL_EFFECT_CAST_BUTTON
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 98 SPELL_EFFECT_KNOCK_BACK
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 99 SPELL_EFFECT_DISENCHANT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 100 SPELL_EFFECT_INEBRIATE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 101 SPELL_EFFECT_FEED_PET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 102 SPELL_EFFECT_DISMISS_PET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 103 SPELL_EFFECT_REPUTATION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 105 SPELL_EFFECT_SURVEY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 106 SPELL_EFFECT_CHANGE_RAID_MARKER
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 107 SPELL_EFFECT_SHOW_CORPSE_LOOT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 108 SPELL_EFFECT_DISPEL_MECHANIC
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 109 SPELL_EFFECT_RESURRECT_PET
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 111 SPELL_EFFECT_DURABILITY_DAMAGE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 112 SPELL_EFFECT_112
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 113 SPELL_EFFECT_CANCEL_CONVERSATION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 114 SPELL_EFFECT_ATTACK_ME
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.CorpseEnemy), // 116 SPELL_EFFECT_SKIN_PLAYER_CORPSE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 117 SPELL_EFFECT_SPIRIT_HEAL
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 118 SPELL_EFFECT_SKILL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 119 SPELL_EFFECT_APPLY_AREA_AURA_PET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 120 SPELL_EFFECT_TELEPORT_GRAVEYARD
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 122 SPELL_EFFECT_122
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 123 SPELL_EFFECT_SEND_TAXI
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 124 SPELL_EFFECT_PULL_TOWARDS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 127 SPELL_EFFECT_PROSPECTING
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 130 SPELL_EFFECT_REDIRECT_THREAT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 131 SPELL_EFFECT_PLAY_SOUND
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 132 SPELL_EFFECT_PLAY_MUSIC
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 133 SPELL_EFFECT_UNLEARN_SPECIALIZATION
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 134 SPELL_EFFECT_KILL_CREDIT2
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 135 SPELL_EFFECT_CALL_PET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 136 SPELL_EFFECT_HEAL_PCT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 137 SPELL_EFFECT_ENERGIZE_PCT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 138 SPELL_EFFECT_LEAP_BACK
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 139 SPELL_EFFECT_CLEAR_QUEST
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 140 SPELL_EFFECT_FORCE_CAST
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 141 SPELL_EFFECT_FORCE_CAST_WITH_VALUE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 144 SPELL_EFFECT_KNOCK_BACK_DEST
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 145 SPELL_EFFECT_PULL_TOWARDS_DEST
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 146 SPELL_EFFECT_RESTORE_GARRISON_TROOP_VITALITY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 147 SPELL_EFFECT_QUEST_FAIL
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 148 SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 149 SPELL_EFFECT_CHARGE_DEST
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 150 SPELL_EFFECT_QUEST_START
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 151 SPELL_EFFECT_TRIGGER_SPELL_2
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 152 SPELL_EFFECT_SUMMON_RAF_FRIEND
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 153 SPELL_EFFECT_CREATE_TAMED_PET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 154 SPELL_EFFECT_DISCOVER_TAXI
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Unit), // 155 SPELL_EFFECT_TITAN_GRIP
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 157 SPELL_EFFECT_CREATE_LOOT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 158 SPELL_EFFECT_MILLING
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 159 SPELL_EFFECT_ALLOW_RENAME_PET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 160 SPELL_EFFECT_160
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 161 SPELL_EFFECT_TALENT_SPEC_COUNT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 162 SPELL_EFFECT_TALENT_SPEC_SELECT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 163 SPELL_EFFECT_OBLITERATE_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 164 SPELL_EFFECT_REMOVE_AURA
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 165 SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT
new StaticData(SpellEffectImplicitTargetTypes.Caster, SpellTargetObjectTypes.Unit), // 166 SPELL_EFFECT_GIVE_CURRENCY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 167 SPELL_EFFECT_UPDATE_PLAYER_PHASE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 168 SPELL_EFFECT_ALLOW_CONTROL_PET
new StaticData(SpellEffectImplicitTargetTypes.Caster, SpellTargetObjectTypes.Unit), // 169 SPELL_EFFECT_DESTROY_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 170 SPELL_EFFECT_UPDATE_ZONE_AURAS_AND_PHASES
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 171 SPELL_EFFECT_SUMMON_PERSONAL_GAMEOBJECT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.CorpseAlly), // 172 SPELL_EFFECT_RESURRECT_WITH_AURA
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 173 SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 174 SPELL_EFFECT_APPLY_AURA_ON_PET
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 175 SPELL_EFFECT_175
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 176 SPELL_EFFECT_SANCTUARY_2
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 177 SPELL_EFFECT_DESPAWN_PERSISTENT_AREA_AURA
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 178 SPELL_EFFECT_178
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 179 SPELL_EFFECT_CREATE_AREATRIGGER
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 180 SPELL_EFFECT_UPDATE_AREATRIGGER
new StaticData(SpellEffectImplicitTargetTypes.Caster, SpellTargetObjectTypes.Unit), // 181 SPELL_EFFECT_REMOVE_TALENT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 182 SPELL_EFFECT_DESPAWN_AREATRIGGER
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 183 SPELL_EFFECT_183
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 184 SPELL_EFFECT_REPUTATION_2
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 185 SPELL_EFFECT_185
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 186 SPELL_EFFECT_186
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 187 SPELL_EFFECT_RANDOMIZE_ARCHAEOLOGY_DIGSITES
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Dest), // 188 SPELL_EFFECT_SUMMON_STABLED_PET_AS_GUARDIAN
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 189 SPELL_EFFECT_LOOT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 190 SPELL_EFFECT_CHANGE_PARTY_MEMBERS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 191 SPELL_EFFECT_TELEPORT_TO_DIGSITE
new StaticData(SpellEffectImplicitTargetTypes.Caster, SpellTargetObjectTypes.Unit), // 192 SPELL_EFFECT_UNCAGE_BATTLEPET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 193 SPELL_EFFECT_START_PET_BATTLE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 194 SPELL_EFFECT_194
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 195 SPELL_EFFECT_PLAY_SCENE_SCRIPT_PACKAGE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 196 SPELL_EFFECT_CREATE_SCENE_OBJECT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 197 SPELL_EFFECT_CREATE_PERSONAL_SCENE_OBJECT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 198 SPELL_EFFECT_PLAY_SCENE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 199 SPELL_EFFECT_DESPAWN_SUMMON
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 200 SPELL_EFFECT_HEAL_BATTLEPET_PCT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 201 SPELL_EFFECT_ENABLE_BATTLE_PETS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 202 SPELL_EFFECT_APPLY_AREA_AURA_SUMMONS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 203 SPELL_EFFECT_REMOVE_AURA_2
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 204 SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 205 SPELL_EFFECT_LAUNCH_QUEST_CHOICE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 206 SPELL_EFFECT_ALTER_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 207 SPELL_EFFECT_LAUNCH_QUEST_TASK
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 208 SPELL_EFFECT_SET_REPUTATION
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 209 SPELL_EFFECT_209
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 210 SPELL_EFFECT_LEARN_GARRISON_BUILDING
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 211 SPELL_EFFECT_LEARN_GARRISON_SPECIALIZATION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 212 SPELL_EFFECT_REMOVE_AURA_BY_SPELL_LABEL
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 213 SPELL_EFFECT_JUMP_DEST_2
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 214 SPELL_EFFECT_CREATE_GARRISON
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 215 SPELL_EFFECT_UPGRADE_CHARACTER_SPELLS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 216 SPELL_EFFECT_CREATE_SHIPMENT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 217 SPELL_EFFECT_UPGRADE_GARRISON
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 218 SPELL_EFFECT_218
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 219 SPELL_EFFECT_CREATE_CONVERSATION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 220 SPELL_EFFECT_ADD_GARRISON_FOLLOWER
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 221 SPELL_EFFECT_ADD_GARRISON_MISSION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 222 SPELL_EFFECT_CREATE_HEIRLOOM_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 223 SPELL_EFFECT_CHANGE_ITEM_BONUSES
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 224 SPELL_EFFECT_ACTIVATE_GARRISON_BUILDING
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 225 SPELL_EFFECT_GRANT_BATTLEPET_LEVEL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 226 SPELL_EFFECT_TRIGGER_ACTION_SET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 227 SPELL_EFFECT_TELEPORT_TO_LFG_DUNGEON
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 228 SPELL_EFFECT_228
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 229 SPELL_EFFECT_SET_FOLLOWER_QUALITY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 230 SPELL_EFFECT_230
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 231 SPELL_EFFECT_INCREASE_FOLLOWER_EXPERIENCE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 232 SPELL_EFFECT_REMOVE_PHASE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 233 SPELL_EFFECT_RANDOMIZE_FOLLOWER_ABILITIES
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 234 SPELL_EFFECT_234
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 235 SPELL_EFFECT_235
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 236 SPELL_EFFECT_GIVE_EXPERIENCE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 237 SPELL_EFFECT_GIVE_RESTED_EXPERIENCE_BONUS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 238 SPELL_EFFECT_INCREASE_SKILL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 239 SPELL_EFFECT_END_GARRISON_BUILDING_CONSTRUCTION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 240 SPELL_EFFECT_GIVE_ARTIFACT_POWER
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 241 SPELL_EFFECT_241
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 242 SPELL_EFFECT_GIVE_ARTIFACT_POWER_NO_BONUS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 243 SPELL_EFFECT_APPLY_ENCHANT_ILLUSION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 244 SPELL_EFFECT_LEARN_FOLLOWER_ABILITY
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 245 SPELL_EFFECT_UPGRADE_HEIRLOOM
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 246 SPELL_EFFECT_FINISH_GARRISON_MISSION
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 247 SPELL_EFFECT_ADD_GARRISON_MISSION_SET
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 248 SPELL_EFFECT_FINISH_SHIPMENT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 249 SPELL_EFFECT_FORCE_EQUIP_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 250 SPELL_EFFECT_TAKE_SCREENSHOT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 251 SPELL_EFFECT_SET_GARRISON_CACHE_SIZE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.UnitAndDest), // 252 SPELL_EFFECT_TELEPORT_UNITS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 253 SPELL_EFFECT_GIVE_HONOR
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.Dest), // 254 SPELL_EFFECT_JUMP_CHARGE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 255 SPELL_EFFECT_LEARN_TRANSMOG_SET
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 256 SPELL_EFFECT_256
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 257 SPELL_EFFECT_257
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 258 SPELL_EFFECT_MODIFY_KEYSTONE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 259 SPELL_EFFECT_RESPEC_AZERITE_EMPOWERED_ITEM
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 260 SPELL_EFFECT_SUMMON_STABLED_PET
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 261 SPELL_EFFECT_SCRAP_ITEM
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 262 SPELL_EFFECT_262
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 263 SPELL_EFFECT_REPAIR_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 264 SPELL_EFFECT_REMOVE_GEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 265 SPELL_EFFECT_LEARN_AZERITE_ESSENCE_POWER
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 266 SPELL_EFFECT_SET_ITEM_BONUS_LIST_GROUP_ENTRY
new StaticData(SpellEffectImplicitTargetTypes.Caster, SpellTargetObjectTypes.Unit), // 267 SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 268 SPELL_EFFECT_APPLY_MOUNT_EQUIPMENT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 269 SPELL_EFFECT_INCREASE_ITEM_BONUS_LIST_GROUP_STEP
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 270 SPELL_EFFECT_270
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 271 SPELL_EFFECT_APPLY_AREA_AURA_PARTY_NONRANDOM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 272 SPELL_EFFECT_SET_COVENANT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 273 SPELL_EFFECT_CRAFT_RUNEFORGE_LEGENDARY
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 274 SPELL_EFFECT_274
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 275 SPELL_EFFECT_275
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 276 SPELL_EFFECT_LEARN_TRANSMOG_ILLUSION
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 277 SPELL_EFFECT_SET_CHROMIE_TIME
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 278 SPELL_EFFECT_278
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 279 SPELL_EFFECT_LEARN_GARR_TALENT
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 280 SPELL_EFFECT_280
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 281 SPELL_EFFECT_LEARN_SOULBIND_CONDUIT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 282 SPELL_EFFECT_CONVERT_ITEMS_TO_CURRENCY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 283 SPELL_EFFECT_COMPLETE_CAMPAIGN
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 284 SPELL_EFFECT_SEND_CHAT_MESSAGE
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 285 SPELL_EFFECT_MODIFY_KEYSTONE_2
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 286 SPELL_EFFECT_GRANT_BATTLEPET_EXPERIENCE
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 287 SPELL_EFFECT_SET_GARRISON_FOLLOWER_LEVEL
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 288 SPELL_EFFECT_CRAFT_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 289 SPELL_EFFECT_MODIFY_AURA_STACKS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 290 SPELL_EFFECT_MODIFY_COOLDOWN
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 291 SPELL_EFFECT_MODIFY_COOLDOWNS
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 292 SPELL_EFFECT_MODIFY_COOLDOWNS_BY_CATEGORY
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 293 SPELL_EFFECT_MODIFY_CHARGES
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 294 SPELL_EFFECT_CRAFT_LOOT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 295 SPELL_EFFECT_SALVAGE_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 296 SPELL_EFFECT_CRAFT_SALVAGE_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 297 SPELL_EFFECT_RECRAFT_ITEM
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 298 SPELL_EFFECT_CANCEL_ALL_PRIVATE_CONVERSATIONS
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 299 SPELL_EFFECT_299
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 300 SPELL_EFFECT_300
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 301 SPELL_EFFECT_CRAFT_ENCHANT
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.None), // 302 SPELL_EFFECT_GATHERING
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 303 SPELL_EFFECT_CREATE_TRAIT_TREE_CONFIG
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 304 SPELL_EFFECT_CHANGE_ACTIVE_COMBAT_TRAIT_CONFIG
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 305 SPELL_EFFECT_305
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 306 SPELL_EFFECT_UPDATE_INTERACTIONS
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 307 SPELL_EFFECT_307
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 308 SPELL_EFFECT_CANCEL_PRELOAD_WORLD
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 309 SPELL_EFFECT_PRELOAD_WORLD
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 310 SPELL_EFFECT_310
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 311 SPELL_EFFECT_ENSURE_WORLD_LOADED
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 312 SPELL_EFFECT_312
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 313 SPELL_EFFECT_CHANGE_ITEM_BONUSES_2
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 314 SPELL_EFFECT_ADD_SOCKET_BONUS
new StaticData(SpellEffectImplicitTargetTypes.Caster, SpellTargetObjectTypes.Unit), // 315 SPELL_EFFECT_LEARN_TRANSMOG_APPEARANCE_FROM_ITEM_MOD_APPEARANCE_GROUP
};
#region Fields
SpellInfo _spellInfo;
public uint EffectIndex;
public SpellEffectName Effect;
public AuraType ApplyAuraName;
public uint ApplyAuraPeriod;
public float BasePoints;
public float RealPointsPerLevel;
public float PointsPerResource;
public float Amplitude;
public float ChainAmplitude;
public float BonusCoefficient;
public int MiscValue;
public int MiscValueB;
public Mechanics Mechanic;
public float PositionFacing;
public SpellImplicitTargetInfo TargetA = new();
public SpellImplicitTargetInfo TargetB = new();
public SpellRadiusRecord TargetARadiusEntry;
public SpellRadiusRecord TargetBRadiusEntry;
public int ChainTargets;
public uint ItemType;
public uint TriggerSpell;
public FlagArray128 SpellClassMask;
public float BonusCoefficientFromAP;
public List<Condition> ImplicitTargetConditions;
public SpellEffectAttributes EffectAttributes;
public ScalingInfo Scaling;
ImmunityInfo _immunityInfo;
#endregion
public struct ScalingInfo
{
public int Class;
public float Coefficient;
public float Variance;
public float ResourceCoefficient;
}
}
public class SpellImplicitTargetInfo
{
public SpellImplicitTargetInfo(Targets target = 0)
{
_target = target;
}
public bool IsArea()
{
return GetSelectionCategory() == SpellTargetSelectionCategories.Area || GetSelectionCategory() == SpellTargetSelectionCategories.Cone;
}
public SpellTargetSelectionCategories GetSelectionCategory()
{
return _data[(int)_target].SelectionCategory;
}
public SpellTargetReferenceTypes GetReferenceType()
{
return _data[(int)_target].ReferenceType;
}
public SpellTargetObjectTypes GetObjectType()
{
return _data[(int)_target].ObjectType;
}
public SpellTargetCheckTypes GetCheckType()
{
return _data[(int)_target].SelectionCheckType;
}
SpellTargetDirectionTypes GetDirectionType()
{
return _data[(int)_target].DirectionType;
}
public float CalcDirectionAngle()
{
float pi = MathFunctions.PI;
switch (GetDirectionType())
{
case SpellTargetDirectionTypes.Front:
return 0.0f;
case SpellTargetDirectionTypes.Back:
return pi;
case SpellTargetDirectionTypes.Right:
return -pi / 2;
case SpellTargetDirectionTypes.Left:
return pi / 2;
case SpellTargetDirectionTypes.FrontRight:
return -pi / 4;
case SpellTargetDirectionTypes.BackRight:
return -3 * pi / 4;
case SpellTargetDirectionTypes.BackLeft:
return 3 * pi / 4;
case SpellTargetDirectionTypes.FrontLeft:
return pi / 4;
case SpellTargetDirectionTypes.Random:
return RandomHelper.NextSingle() * (2 * pi);
default:
return 0.0f;
}
}
public Targets GetTarget()
{
return _target;
}
public SpellCastTargetFlags GetExplicitTargetMask(ref bool srcSet, ref bool dstSet)
{
SpellCastTargetFlags targetMask = 0;
if (GetTarget() == Targets.DestTraj)
{
if (!srcSet)
targetMask = SpellCastTargetFlags.SourceLocation;
if (!dstSet)
targetMask |= SpellCastTargetFlags.DestLocation;
}
else
{
switch (GetReferenceType())
{
case SpellTargetReferenceTypes.Src:
if (srcSet)
break;
targetMask = SpellCastTargetFlags.SourceLocation;
break;
case SpellTargetReferenceTypes.Dest:
if (dstSet)
break;
targetMask = SpellCastTargetFlags.DestLocation;
break;
case SpellTargetReferenceTypes.Target:
switch (GetObjectType())
{
case SpellTargetObjectTypes.Gobj:
targetMask = SpellCastTargetFlags.Gameobject;
break;
case SpellTargetObjectTypes.GobjItem:
targetMask = SpellCastTargetFlags.GameobjectItem;
break;
case SpellTargetObjectTypes.UnitAndDest:
case SpellTargetObjectTypes.Unit:
case SpellTargetObjectTypes.Dest:
switch (GetCheckType())
{
case SpellTargetCheckTypes.Enemy:
targetMask = SpellCastTargetFlags.UnitEnemy;
break;
case SpellTargetCheckTypes.Ally:
targetMask = SpellCastTargetFlags.UnitAlly;
break;
case SpellTargetCheckTypes.Party:
targetMask = SpellCastTargetFlags.UnitParty;
break;
case SpellTargetCheckTypes.Raid:
targetMask = SpellCastTargetFlags.UnitRaid;
break;
case SpellTargetCheckTypes.Passenger:
targetMask = SpellCastTargetFlags.UnitPassenger;
break;
case SpellTargetCheckTypes.RaidClass:
default:
targetMask = SpellCastTargetFlags.Unit;
break;
}
break;
default:
break;
}
break;
default:
break;
}
}
switch (GetObjectType())
{
case SpellTargetObjectTypes.Src:
srcSet = true;
break;
case SpellTargetObjectTypes.Dest:
case SpellTargetObjectTypes.UnitAndDest:
dstSet = true;
break;
default:
break;
}
return targetMask;
}
Targets _target;
public struct StaticData
{
public StaticData(SpellTargetObjectTypes obj, SpellTargetReferenceTypes reference,
SpellTargetSelectionCategories selection, SpellTargetCheckTypes selectionCheck, SpellTargetDirectionTypes direction)
{
ObjectType = obj;
ReferenceType = reference;
SelectionCategory = selection;
SelectionCheckType = selectionCheck;
DirectionType = direction;
}
public SpellTargetObjectTypes ObjectType; // type of object returned by target type
public SpellTargetReferenceTypes ReferenceType; // defines which object is used as a reference when selecting target
public SpellTargetSelectionCategories SelectionCategory;
public SpellTargetCheckTypes SelectionCheckType; // defines selection criteria
public SpellTargetDirectionTypes DirectionType; // direction for cone and dest targets
}
static StaticData[] _data = new StaticData[(int)Targets.TotalSpellTargets]
{
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 0
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 1 TARGET_UNIT_CASTER
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 2 TARGET_UNIT_NEARBY_ENEMY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 3 TARGET_UNIT_NEARBY_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Party, SpellTargetDirectionTypes.None), // 4 TARGET_UNIT_NEARBY_PARTY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 5 TARGET_UNIT_PET
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 6 TARGET_UNIT_TARGET_ENEMY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Src, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Entry, SpellTargetDirectionTypes.None), // 7 TARGET_UNIT_SRC_AREA_ENTRY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Entry, SpellTargetDirectionTypes.None), // 8 TARGET_UNIT_DEST_AREA_ENTRY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 9 TARGET_DEST_HOME
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 10
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Src, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 11 TARGET_UNIT_SRC_AREA_UNK_11
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 12
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 13
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 14
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Src, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 15 TARGET_UNIT_SRC_AREA_ENEMY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 16 TARGET_UNIT_DEST_AREA_ENEMY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 17 TARGET_DEST_DB
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 18 TARGET_DEST_CASTER
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 19
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Party, SpellTargetDirectionTypes.None), // 20 TARGET_UNIT_CASTER_AREA_PARTY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 21 TARGET_UNIT_TARGET_ALLY
new StaticData(SpellTargetObjectTypes.Src, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 22 TARGET_SRC_CASTER
new StaticData(SpellTargetObjectTypes.Gobj, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 23 TARGET_GAMEOBJECT_TARGET
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.Front), // 24 TARGET_UNIT_CONE_ENEMY_24
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 25 TARGET_UNIT_TARGET_ANY
new StaticData(SpellTargetObjectTypes.GobjItem, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 26 TARGET_GAMEOBJECT_ITEM_TARGET
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 27 TARGET_UNIT_MASTER
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 28 TARGET_DEST_DYNOBJ_ENEMY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 29 TARGET_DEST_DYNOBJ_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Src, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 30 TARGET_UNIT_SRC_AREA_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 31 TARGET_UNIT_DEST_AREA_ALLY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.FrontLeft), // 32 TARGET_DEST_CASTER_SUMMON
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Src, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Party, SpellTargetDirectionTypes.None), // 33 TARGET_UNIT_SRC_AREA_PARTY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Party, SpellTargetDirectionTypes.None), // 34 TARGET_UNIT_DEST_AREA_PARTY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Party, SpellTargetDirectionTypes.None), // 35 TARGET_UNIT_TARGET_PARTY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 36 TARGET_DEST_CASTER_UNK_36
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Last, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Party, SpellTargetDirectionTypes.None), // 37 TARGET_UNIT_LASTTARGET_AREA_PARTY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Entry, SpellTargetDirectionTypes.None), // 38 TARGET_UNIT_NEARBY_ENTRY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 39 TARGET_DEST_CASTER_FISHING
new StaticData(SpellTargetObjectTypes.Gobj, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Entry, SpellTargetDirectionTypes.None), // 40 TARGET_GAMEOBJECT_NEARBY_ENTRY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.FrontRight), // 41 TARGET_DEST_CASTER_FRONT_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.BackRight), // 42 TARGET_DEST_CASTER_BACK_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.BackLeft), // 43 TARGET_DEST_CASTER_BACK_LEFT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.FrontLeft), // 44 TARGET_DEST_CASTER_FRONT_LEFT
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 45 TARGET_UNIT_TARGET_CHAINHEAL_ALLY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Entry, SpellTargetDirectionTypes.None), // 46 TARGET_DEST_NEARBY_ENTRY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Front), // 47 TARGET_DEST_CASTER_FRONT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Back), // 48 TARGET_DEST_CASTER_BACK
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Right), // 49 TARGET_DEST_CASTER_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Left), // 50 TARGET_DEST_CASTER_LEFT
new StaticData(SpellTargetObjectTypes.Gobj, SpellTargetReferenceTypes.Src, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 51 TARGET_GAMEOBJECT_SRC_AREA
new StaticData(SpellTargetObjectTypes.Gobj, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 52 TARGET_GAMEOBJECT_DEST_AREA
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 53 TARGET_DEST_TARGET_ENEMY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.Front), // 54 TARGET_UNIT_CONE_180_DEG_ENEMY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 55 TARGET_DEST_CASTER_FRONT_LEAP
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Raid, SpellTargetDirectionTypes.None), // 56 TARGET_UNIT_CASTER_AREA_RAID
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Raid, SpellTargetDirectionTypes.None), // 57 TARGET_UNIT_TARGET_RAID
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Raid, SpellTargetDirectionTypes.None), // 58 TARGET_UNIT_NEARBY_RAID
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.Front), // 59 TARGET_UNIT_CONE_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Entry, SpellTargetDirectionTypes.Front), // 60 TARGET_UNIT_CONE_ENTRY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.RaidClass,SpellTargetDirectionTypes.None), // 61 TARGET_UNIT_TARGET_AREA_RAID_CLASS
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 62 TARGET_DEST_CASTER_GROUND
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 63 TARGET_DEST_TARGET_ANY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Front), // 64 TARGET_DEST_TARGET_FRONT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Back), // 65 TARGET_DEST_TARGET_BACK
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Right), // 66 TARGET_DEST_TARGET_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Left), // 67 TARGET_DEST_TARGET_LEFT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.FrontRight), // 68 TARGET_DEST_TARGET_FRONT_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.BackRight), // 69 TARGET_DEST_TARGET_BACK_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.BackLeft), // 70 TARGET_DEST_TARGET_BACK_LEFT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.FrontLeft), // 71 TARGET_DEST_TARGET_FRONT_LEFT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Random), // 72 TARGET_DEST_CASTER_RANDOM
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Random), // 73 TARGET_DEST_CASTER_RADIUS
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Random), // 74 TARGET_DEST_TARGET_RANDOM
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Random), // 75 TARGET_DEST_TARGET_RADIUS
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Channel, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 76 TARGET_DEST_CHANNEL_TARGET
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Channel, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 77 TARGET_UNIT_CHANNEL_TARGET
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Front), // 78 TARGET_DEST_DEST_FRONT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Back), // 79 TARGET_DEST_DEST_BACK
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Right), // 80 TARGET_DEST_DEST_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Left), // 81 TARGET_DEST_DEST_LEFT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.FrontRight), // 82 TARGET_DEST_DEST_FRONT_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.BackRight), // 83 TARGET_DEST_DEST_BACK_RIGHT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.BackLeft), // 84 TARGET_DEST_DEST_BACK_LEFT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.FrontLeft), // 85 TARGET_DEST_DEST_FRONT_LEFT
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Random), // 86 TARGET_DEST_DEST_RANDOM
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 87 TARGET_DEST_DEST
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 88 TARGET_DEST_DYNOBJ_NONE
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Traj , SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 89 TARGET_DEST_TRAJ
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 90 TARGET_UNIT_TARGET_MINIPET
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Random), // 91 TARGET_DEST_DEST_RADIUS
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 92 TARGET_UNIT_SUMMONER
new StaticData(SpellTargetObjectTypes.Corpse, SpellTargetReferenceTypes.Src, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 93 TARGET_CORPSE_SRC_AREA_ENEMY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 94 TARGET_UNIT_VEHICLE
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Passenger,SpellTargetDirectionTypes.None), // 95 TARGET_UNIT_TARGET_PASSENGER
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 96 TARGET_UNIT_PASSENGER_0
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 97 TARGET_UNIT_PASSENGER_1
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 98 TARGET_UNIT_PASSENGER_2
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 99 TARGET_UNIT_PASSENGER_3
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 100 TARGET_UNIT_PASSENGER_4
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 101 TARGET_UNIT_PASSENGER_5
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 102 TARGET_UNIT_PASSENGER_6
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 103 TARGET_UNIT_PASSENGER_7
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.Front), // 104 TARGET_UNIT_CONE_CASTER_TO_DEST_ENEMY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 105 TARGET_UNIT_CASTER_AND_PASSENGERS
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Channel, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 106 TARGET_DEST_CHANNEL_CASTER
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Entry, SpellTargetDirectionTypes.None), // 107 TARGET_DEST_NEARBY_ENTRY_2
new StaticData(SpellTargetObjectTypes.Gobj, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.Front), // 108 TARGET_GAMEOBJECT_CONE_CASTER_TO_DEST_ENEMY
new StaticData(SpellTargetObjectTypes.Gobj, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.Front), // 109 TARGET_GAMEOBJECT_CONE_CASTER_TO_DEST_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Entry , SpellTargetDirectionTypes.Front), // 110 TARGET_UNIT_CONE_CASTER_TO_DEST_ENTRY
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 111
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 112
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 113
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 114
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Src, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 115 TARGET_UNIT_SRC_AREA_FURTHEST_ENEMY
new StaticData(SpellTargetObjectTypes.UnitAndDest, SpellTargetReferenceTypes.Last, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 116 TARGET_UNIT_AND_DEST_LAST_ENEMY
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 117
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Raid, SpellTargetDirectionTypes.None), // 118 TARGET_UNIT_TARGET_ALLY_OR_RAID
new StaticData(SpellTargetObjectTypes.Corpse, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Raid, SpellTargetDirectionTypes.None), // 119 TARGET_CORPSE_SRC_AREA_RAID
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Summoned, SpellTargetDirectionTypes.None), // 120 TARGET_UNIT_SELF_AND_SUMMONS
new StaticData(SpellTargetObjectTypes.Corpse, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 121 TARGET_CORPSE_TARGET_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 122 TARGET_UNIT_AREA_THREAT_LIST
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 123 TARGET_UNIT_AREA_TAP_LIST
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 124 TARGET_UNIT_TARGET_TAP_LIST
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 125 TARGET_DEST_CASTER_GROUND_2
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 126 TARGET_UNIT_CASTER_AREA_ENEMY_CLUMP
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 127 TARGET_DEST_CASTER_ENEMY_CLUMP_CENTROID
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.Front), // 128 TARGET_UNIT_RECT_CASTER_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.Front), // 129 TARGET_UNIT_RECT_CASTER_ENEMY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Front), // 130 TARGET_UNIT_RECT_CASTER
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 131 TARGET_DEST_SUMMONER
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Target, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 132 TARGET_DEST_TARGET_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Line, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.None), // 133 TARGET_UNIT_LINE_CASTER_TO_DEST_ALLY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Line, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 134 TARGET_UNIT_LINE_CASTER_TO_DEST_ENEMY
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Line, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 135 TARGET_UNIT_LINE_CASTER_TO_DEST
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Cone, SpellTargetCheckTypes.Ally, SpellTargetDirectionTypes.Front), // 136 TARGET_UNIT_CONE_CASTER_TO_DEST_ALLY
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 137 TARGET_DEST_CASTER_MOVEMENT_DIRECTION
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 138 TARGET_DEST_DEST_GROUND
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 139
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 140 TARGET_DEST_CASTER_CLUMP_CENTROID
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 141
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Nearby, SpellTargetCheckTypes.Entry, SpellTargetDirectionTypes.FrontRight), // 142 TARGET_DEST_NEARBY_ENTRY_OR_DB
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 143
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 144
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 145
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 146
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 147
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Dest, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 148 TARGET_DEST_DEST_TARGET_TOWARDS_CASTER
new StaticData(SpellTargetObjectTypes.Dest, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.Random), // 149
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Default, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 150 TARGET_UNIT_OWN_CRITTER
new StaticData(SpellTargetObjectTypes.Unit, SpellTargetReferenceTypes.Caster, SpellTargetSelectionCategories.Area, SpellTargetCheckTypes.Enemy, SpellTargetDirectionTypes.None), // 151
new StaticData(SpellTargetObjectTypes.None, SpellTargetReferenceTypes.None, SpellTargetSelectionCategories.Nyi, SpellTargetCheckTypes.Default, SpellTargetDirectionTypes.None), // 152
};
}
public class SpellPowerCost
{
public PowerType Power;
public int Amount;
}
class SpellDiminishInfo
{
public DiminishingGroup DiminishGroup = DiminishingGroup.None;
public DiminishingReturnsType DiminishReturnType = DiminishingReturnsType.None;
public DiminishingLevels DiminishMaxLevel = DiminishingLevels.Immune;
public int DiminishDurationLimit;
}
public class ImmunityInfo
{
public uint SchoolImmuneMask;
public uint ApplyHarmfulAuraImmuneMask;
public ulong MechanicImmuneMask;
public uint DispelImmuneMask;
public uint DamageSchoolMask;
public byte OtherImmuneMask;
public List<AuraType> AuraTypeImmune = new();
public List<SpellEffectName> SpellEffectImmune = new();
}
}