2590e31d57
Port From (https://github.com/TrinityCore/TrinityCore/commit/df511503815b7798c83acbffbb1ce5208f189ce7)
5167 lines
277 KiB
C#
5167 lines
277 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 IsAutocastEnabledByDefault()
|
|
{
|
|
return !HasAttribute(SpellAttr9.AutocastOffByDefault);
|
|
}
|
|
|
|
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)
|
|
{
|
|
// 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;
|
|
|
|
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();
|
|
if (auraSpellInfo.Id == Id) // Don't remove self
|
|
return false;
|
|
if (auraSpellInfo.IsPassive()) // Don't remove passive auras
|
|
return false;
|
|
if (((uint)auraSpellInfo.GetSchoolMask() & schoolImmunity) == 0) // Check for school mask
|
|
return false;
|
|
if (!CanDispelAura(auraSpellInfo))
|
|
return false;
|
|
if (!HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects))
|
|
{
|
|
WorldObject existingAuraCaster = aurApp.GetBase().GetWorldObjectCaster();
|
|
if (existingAuraCaster != null && existingAuraCaster.IsFriendlyTo(target)) // Check spell vs aura possitivity
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
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 => CanDispelAura(aurApp.GetBase().GetSpellInfo()));
|
|
}
|
|
|
|
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(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.IsAura())
|
|
continue;
|
|
|
|
if (mechanicImmunity != 0)
|
|
if ((mechanicImmunity & (1ul << (int)auraSpellEffectInfo.Mechanic)) != 0)
|
|
continue;
|
|
|
|
AuraType auraName = auraSpellEffectInfo.ApplyAuraName;
|
|
if (auraName != 0)
|
|
{
|
|
if (immuneInfo.AuraTypeImmune.Contains(auraName))
|
|
continue;
|
|
|
|
if (!auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities) && !auraSpellInfo.IsPositiveEffect(auraSpellEffectInfo.EffectIndex))
|
|
{
|
|
uint applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask;
|
|
if (applyHarmfulAuraImmunityMask != 0)
|
|
if (((uint)auraSpellInfo.GetSchoolMask() & applyHarmfulAuraImmunityMask) != 0)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
immuneToAllEffects = false;
|
|
}
|
|
|
|
if (immuneToAllEffects)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CanSpellEffectProvideImmunityAgainstAuraEffect(SpellEffectInfo immunityEffectInfo, SpellInfo auraSpellInfo, SpellEffectInfo auraEffectInfo)
|
|
{
|
|
ImmunityInfo immuneInfo = immunityEffectInfo.GetImmunityInfo();
|
|
if (immuneInfo == null)
|
|
return false;
|
|
|
|
if (!auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
|
|
{
|
|
uint schoolImmunity = immuneInfo.SchoolImmuneMask;
|
|
if (schoolImmunity != 0)
|
|
if (((uint)auraSpellInfo.SchoolMask & schoolImmunity) != 0)
|
|
return true;
|
|
|
|
uint applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask;
|
|
if (applyHarmfulAuraImmunityMask != 0)
|
|
if (((uint)auraSpellInfo.GetSchoolMask() & applyHarmfulAuraImmunityMask) != 0)
|
|
return true;
|
|
}
|
|
|
|
ulong mechanicImmunity = immuneInfo.MechanicImmuneMask;
|
|
if (mechanicImmunity != 0)
|
|
{
|
|
if ((mechanicImmunity & (1ul << (int)auraSpellInfo.Mechanic)) != 0)
|
|
return true;
|
|
if ((mechanicImmunity & (1ul << (int)auraEffectInfo.Mechanic)) != 0)
|
|
return true;
|
|
}
|
|
|
|
uint dispelImmunity = immuneInfo.DispelImmuneMask;
|
|
if (dispelImmunity != 0 && (uint)auraSpellInfo.Dispel == dispelImmunity)
|
|
return true;
|
|
|
|
if (immuneInfo.AuraTypeImmune.Contains(auraEffectInfo.ApplyAuraName))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool SpellCancelsAuraEffect(AuraEffect aurEff)
|
|
{
|
|
if (!HasAttribute(SpellAttr1.ImmunityPurgesEffect))
|
|
return false;
|
|
|
|
if (aurEff.GetSpellInfo().HasAttribute(SpellAttr0.NoImmunities))
|
|
return false;
|
|
|
|
if (aurEff.GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes.NoImmunity))
|
|
return false;
|
|
|
|
foreach (SpellEffectInfo effect in GetEffects())
|
|
if (CanSpellEffectProvideImmunityAgainstAuraEffect(effect, aurEff.GetSpellInfo(), aurEff.GetSpellEffectInfo()))
|
|
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);
|
|
|
|
if (!_spellInfo.HasAttribute(SpellAttr9.NoMovementRadiusBonus))
|
|
if (casterUnit != null && Spell.CanIncreaseRangeByMovement(casterUnit))
|
|
radius += 2.0f;
|
|
}
|
|
|
|
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
|
|
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 316 SPELL_EFFECT_KILL_CREDIT_LABEL_1
|
|
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 317 SPELL_EFFECT_KILL_CREDIT_LABEL_2
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 318 SPELL_EFFECT_318
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 319 SPELL_EFFECT_319
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 320 SPELL_EFFECT_320
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 321 SPELL_EFFECT_321
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 322 SPELL_EFFECT_322
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 323 SPELL_EFFECT_323
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 324 SPELL_EFFECT_324
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 325 SPELL_EFFECT_325
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 326 SPELL_EFFECT_326
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 327 SPELL_EFFECT_327
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 328 SPELL_EFFECT_328
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 329 SPELL_EFFECT_329
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 330 SPELL_EFFECT_330
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 331 SPELL_EFFECT_331
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 332 SPELL_EFFECT_332
|
|
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 333 SPELL_EFFECT_333
|
|
};
|
|
|
|
#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();
|
|
}
|
|
}
|
|
|