Core/Spells: Rename SpellAttr4 to use official attribute names
Port From (https://github.com/TrinityCore/TrinityCore/commit/8d16a79dea4c0100d36e13b068c42499a3a48154)
This commit is contained in:
@@ -1746,6 +1746,7 @@ namespace Framework.Constants
|
|||||||
None = 0,
|
None = 0,
|
||||||
UnaffectedByInvulnerability = 0x01, // not cancelled by immunities
|
UnaffectedByInvulnerability = 0x01, // not cancelled by immunities
|
||||||
NoScaleWithStack = 0x40,
|
NoScaleWithStack = 0x40,
|
||||||
|
ChainFromInitialTarget = 0x80,
|
||||||
StackAuraAmountOnRecast = 0x8000, // refreshing periodic auras with this attribute will add remaining damage to new aura
|
StackAuraAmountOnRecast = 0x8000, // refreshing periodic auras with this attribute will add remaining damage to new aura
|
||||||
AllowAnyExplicitTarget = 0x100000,
|
AllowAnyExplicitTarget = 0x100000,
|
||||||
IgnoreDuringCooldownTimeRateCalculation = 0x800000
|
IgnoreDuringCooldownTimeRateCalculation = 0x800000
|
||||||
|
|||||||
@@ -1723,38 +1723,38 @@ namespace Framework.Constants
|
|||||||
}
|
}
|
||||||
public enum SpellAttr4 : uint
|
public enum SpellAttr4 : uint
|
||||||
{
|
{
|
||||||
IgnoreResistances = 0x01, // 0 Spells With This Attribute Will Completely Ignore The Target'S Resistance (These Spells Can'T Be Resisted)
|
NoCastLog = 0x01, // No Cast Log
|
||||||
ProcOnlyOnCaster = 0x02, // 1 Proc Only On Effects With TargetUnitCaster?
|
ClassTriggerOnlyOnTarget = 0x02, // Class Trigger Only On Target
|
||||||
AuraExpiresOffline = 0x04, // 2 duration is removed from aura while player is logged out
|
AuraExpiresOffline = 0x04, // Aura Expires Offline Description Debuffs (Except Resurrection Sickness) Will Automatically Do This
|
||||||
Unk3 = 0x08, // 3
|
NoHelpfulThreat = 0x08, // No Helpful Threat
|
||||||
Unk4 = 0x10, // 4 This Will No Longer Cause Guards To Attack On Use??
|
NoHarmfulThreat = 0x10, // No Harmful Threat
|
||||||
Unk5 = 0x20, // 5
|
AllowClientTargeting = 0x20, // Allow Client Targeting Description Allows Client To Send Spell Targets For This Spell. Applies Only To Pet Spells, Without This Attribute CmsgPetAction Is Sent Instead Of CmsgPetCastSpell
|
||||||
NotStealable = 0x40, // 6 Although Such Auras Might Be Dispellable, They Cannot Be Stolen
|
CannotBeStolen = 0x40, // Cannot Be Stolen
|
||||||
CanCastWhileCasting = 0x80, // 7 Can be cast while another cast is in progress - see CanCastWhileCasting(SpellRec const*,CGUnit_C *,int &)
|
AllowCastWhileCasting = 0x80, // Allow Cast While Casting Description Ignores Already In-Progress Cast And Still Casts
|
||||||
FixedDamage = 0x100, // 8 Ignores Taken Percent Damage Mods?
|
IgnoreDamageTakenModifiers = 0x100, // Ignore Damage Taken Modifiers
|
||||||
TriggerActivate = 0x200, // 9 Initially Disabled / Trigger Activate From Event (Execute, Riposte, Deep Freeze End Other)
|
CombatFeedbackWhenUsable = 0x200, // Combat Feedback When Usable (Client Only)
|
||||||
SpellVsExtendCost = 0x400, // 10 Rogue Shiv Have This Flag
|
WeaponSpeedCostScaling = 0x400, // Weapon Speed Cost Scaling Description Adds 10 To Power Cost For Each 1s Of Weapon Speed
|
||||||
Unk11 = 0x800, // 11
|
NoPartialImmunity = 0x800, // No Partial Immunity
|
||||||
Unk12 = 0x1000, // 12
|
AuraIsBuff = 0x1000, // Aura Is Buff
|
||||||
CombatLogNoCaster = 0x2000, // 13 No caster object is sent to client combat log
|
DoNotLogCaster = 0x2000, // Do Not Log Caster
|
||||||
DamageDoesntBreakAuras = 0x4000, // 14 Doesn'T Break Auras By Damage From These Spells
|
ReactiveDamageProc = 0x4000, // Reactive Damage Proc Description Damage From Spells With This Attribute Doesn'T Break Auras That Normally Break On Damage Taken
|
||||||
HiddenInSpellbook = 0x8000, // 15
|
NotInSpellbook = 0x8000, // Not In Spellbook
|
||||||
NotUsableInArenaOrRatedBg = 0x10000, // 16 Cannot Be Used In Both Arenas Or Rated Battlegrounds
|
NotInArenaOrRatedBattleground = 0x10000, // Not In Arena Or Rated Battleground Description Makes Spell Unusable Despite Cd <= 10min
|
||||||
UsableInArena = 0x20000, // 17
|
IgnoreDefaultArenaRestrictions = 0x20000, // Ignore Default Arena Restrictions Description Makes Spell Usable Despite Cd > 10min
|
||||||
AreaTargetChain = 0x40000, // 18 (Nyi)Hits Area Targets One After Another Instead Of All At Once
|
BouncyChainMissiles = 0x40000, // Bouncy Chain Missiles Description Hits Area Targets Over Time Instead Of All At Once
|
||||||
Unk19 = 0x80000, // 19 Proc Dalayed, After Damage Or Don'T Proc On Absorb?
|
AllowProcWhileSitting = 0x80000, // Allow Proc While Sitting
|
||||||
NotCheckSelfcastPower = 0x100000, // 20 Supersedes Message "More Powerful Spell Applied" For Self Casts.
|
AuraNeverBounces = 0x100000, // Aura Never Bounces
|
||||||
DontRemoveInArena = 0x200000, // 21 Pally Aura, Dk Presence, Dudu Form, Warrior Stance, Shadowform, Hunter Track
|
AllowEnteringArena = 0x200000, // Allow Entering Arena
|
||||||
Unk22 = 0x400000, // 22 Seal Of Command (42058,57770) And Gymer'S Smash 55426
|
ProcSuppressSwingAnim = 0x400000, // Proc Suppress Swing Anim
|
||||||
SuppressWeaponProcs = 0x800000, // 23 spells with this flag should not trigger item spells / enchants (mostly in conjunction with SPELL_ATTR0_STOP_ATTACK_TARGET)
|
SuppressWeaponProcs = 0x800000, // Suppress Weapon Procs
|
||||||
Unk24 = 0x1000000, // 24 Some Shoot Spell
|
AutoRangedCombat = 0x1000000, // Auto Ranged Combat
|
||||||
IsPetScaling = 0x2000000, // 25 Pet Scaling Auras
|
OwnerPowerScaling = 0x2000000, // Owner Power Scaling
|
||||||
CastOnlyInOutland = 0x4000000, // 26 Can Only Be Used In Outland.
|
OnlyFlyingAreas = 0x4000000, // Only Flying Areas
|
||||||
Unk27 = 0x8000000, // 27
|
ForceDisplayCastbar = 0x8000000, // Force Display Castbar
|
||||||
Unk28 = 0x10000000, // 28 Aimed Shot
|
IgnoreCombatTimer = 0x10000000, // Ignore Combat Timer
|
||||||
Unk29 = 0x20000000, // 29
|
AuraBounceFailsSpell = 0x20000000, // Aura Bounce Fails Spell
|
||||||
Unk30 = 0x40000000, // 30
|
Obsolete = 0x40000000, // Obsolete
|
||||||
Unk31 = 0x80000000 // 31 Polymorph (Chicken) 228 And Sonic Boom (38052,38488)
|
UseFacingFromSpell = 0x80000000 // Use Facing From Spell
|
||||||
}
|
}
|
||||||
public enum SpellAttr5 : uint
|
public enum SpellAttr5 : uint
|
||||||
{
|
{
|
||||||
@@ -1770,7 +1770,7 @@ namespace Framework.Constants
|
|||||||
StartPeriodicAtApply = 0x200, // 9 Begin Periodic Tick At Aura Apply
|
StartPeriodicAtApply = 0x200, // 9 Begin Periodic Tick At Aura Apply
|
||||||
HideDuration = 0x400, // 10 Do Not Send Duration To Client
|
HideDuration = 0x400, // 10 Do Not Send Duration To Client
|
||||||
AllowTargetOfTargetAsTarget = 0x800, // 11 (Nyi) Uses Target'S Target As Target If Original Target Not Valid (Intervene For Example)
|
AllowTargetOfTargetAsTarget = 0x800, // 11 (Nyi) Uses Target'S Target As Target If Original Target Not Valid (Intervene For Example)
|
||||||
Unk12 = 0x1000, // 12 Cleave Related?
|
MeleeChainTargeting = 0x1000, // 12 Cleave Related?
|
||||||
HasteAffectDuration = 0x2000, // 13 Haste Effects Decrease Duration Of This
|
HasteAffectDuration = 0x2000, // 13 Haste Effects Decrease Duration Of This
|
||||||
NotUsableWhileCharmed = 0x4000, // 14 Charmed units cannot cast this spell
|
NotUsableWhileCharmed = 0x4000, // 14 Charmed units cannot cast this spell
|
||||||
Unk15 = 0x8000, // 15 Inflits On Multiple Targets?
|
Unk15 = 0x8000, // 15 Inflits On Multiple Targets?
|
||||||
|
|||||||
@@ -590,7 +590,7 @@ namespace Game.Combat
|
|||||||
|
|
||||||
public void ForwardThreatForAssistingMe(Unit assistant, float baseAmount, SpellInfo spell = null, bool ignoreModifiers = false)
|
public void ForwardThreatForAssistingMe(Unit assistant, float baseAmount, SpellInfo spell = null, bool ignoreModifiers = false)
|
||||||
{
|
{
|
||||||
if (spell != null && spell.HasAttribute(SpellAttr1.NoThreat)) // shortcut, none of the calls would do anything
|
if (spell != null && (spell.HasAttribute(SpellAttr1.NoThreat) || spell.HasAttribute(SpellAttr4.NoHelpfulThreat))) // shortcut, none of the calls would do anything
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_threatenedByMe.Empty())
|
if (_threatenedByMe.Empty())
|
||||||
|
|||||||
@@ -2088,30 +2088,6 @@ namespace Game.Entities
|
|||||||
ApplySpellImmune(placeholderSpellId, SpellImmunity.School, 1u << i, true);
|
ApplySpellImmune(placeholderSpellId, SpellImmunity.School, 1u << i, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsImmunedToSpell(SpellInfo spellInfo, WorldObject caster)
|
|
||||||
{
|
|
||||||
if (spellInfo == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool immunedToAllEffects = true;
|
|
||||||
foreach (var spellEffectInfo in spellInfo.GetEffects())
|
|
||||||
{
|
|
||||||
if (!spellEffectInfo.IsEffect())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster))
|
|
||||||
{
|
|
||||||
immunedToAllEffects = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (immunedToAllEffects)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return base.IsImmunedToSpell(spellInfo, caster);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, WorldObject caster)
|
public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, SpellEffectInfo spellEffectInfo, WorldObject caster)
|
||||||
{
|
{
|
||||||
if (GetCreatureTemplate().CreatureType == CreatureType.Mechanical && spellEffectInfo.IsEffect(SpellEffectName.Heal))
|
if (GetCreatureTemplate().CreatureType == CreatureType.Mechanical && spellEffectInfo.IsEffect(SpellEffectName.Heal))
|
||||||
|
|||||||
@@ -273,8 +273,8 @@ namespace Game.Entities
|
|||||||
if (cheatDeath.GetMiscValue().HasAnyFlag((int)SpellSchoolMask.Normal))
|
if (cheatDeath.GetMiscValue().HasAnyFlag((int)SpellSchoolMask.Normal))
|
||||||
MathFunctions.AddPct(ref TakenTotalMod, cheatDeath.GetAmount());
|
MathFunctions.AddPct(ref TakenTotalMod, cheatDeath.GetAmount());
|
||||||
|
|
||||||
// Spells with SPELL_ATTR4_FIXED_DAMAGE should only benefit from mechanic damage mod auras.
|
// Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS should only benefit from mechanic damage mod auras.
|
||||||
if (!spellProto.HasAttribute(SpellAttr4.FixedDamage))
|
if (!spellProto.HasAttribute(SpellAttr4.IgnoreDamageTakenModifiers))
|
||||||
{
|
{
|
||||||
// Versatility
|
// Versatility
|
||||||
Player modOwner = GetSpellModOwner();
|
Player modOwner = GetSpellModOwner();
|
||||||
@@ -1216,7 +1216,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public virtual bool IsImmunedToSpell(SpellInfo spellInfo, WorldObject caster)
|
public bool IsImmunedToSpell(SpellInfo spellInfo, WorldObject caster)
|
||||||
{
|
{
|
||||||
if (spellInfo == null)
|
if (spellInfo == null)
|
||||||
return false;
|
return false;
|
||||||
@@ -1259,6 +1259,9 @@ namespace Game.Entities
|
|||||||
immuneToAllEffects = false;
|
immuneToAllEffects = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spellInfo.HasAttribute(SpellAttr4.NoPartialImmunity))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
|
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
|
||||||
@@ -1939,8 +1942,8 @@ namespace Game.Entities
|
|||||||
|
|
||||||
SpellSchoolMask damageSchoolMask = damageInfo.schoolMask;
|
SpellSchoolMask damageSchoolMask = damageInfo.schoolMask;
|
||||||
|
|
||||||
// Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage.
|
// Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS ignore resilience because their damage is based off another spell's damage.
|
||||||
if (!spellInfo.HasAttribute(SpellAttr4.FixedDamage))
|
if (!spellInfo.HasAttribute(SpellAttr4.IgnoreDamageTakenModifiers))
|
||||||
{
|
{
|
||||||
if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
|
if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
|
||||||
damage = (int)CalcArmorReducedDamage(damageInfo.attacker, victim, (uint)damage, spellInfo, attackType);
|
damage = (int)CalcArmorReducedDamage(damageInfo.attacker, victim, (uint)damage, spellInfo, attackType);
|
||||||
@@ -3433,7 +3436,7 @@ namespace Game.Entities
|
|||||||
RemoveAppliedAuras(aurApp =>
|
RemoveAppliedAuras(aurApp =>
|
||||||
{
|
{
|
||||||
Aura aura = aurApp.GetBase();
|
Aura aura = aurApp.GetBase();
|
||||||
return (!aura.GetSpellInfo().HasAttribute(SpellAttr4.DontRemoveInArena) // don't remove stances, shadowform, pally/hunter auras
|
return (!aura.GetSpellInfo().HasAttribute(SpellAttr4.AllowEnteringArena) // don't remove stances, shadowform, pally/hunter auras
|
||||||
&& !aura.IsPassive() // don't remove passive auras
|
&& !aura.IsPassive() // don't remove passive auras
|
||||||
&& (aurApp.IsPositive() || !aura.GetSpellInfo().HasAttribute(SpellAttr3.AllowAuraWhileDead))) || // not negative death persistent auras
|
&& (aurApp.IsPositive() || !aura.GetSpellInfo().HasAttribute(SpellAttr3.AllowAuraWhileDead))) || // not negative death persistent auras
|
||||||
aura.GetSpellInfo().HasAttribute(SpellAttr5.RemoveEnteringArena); // special marker, always remove
|
aura.GetSpellInfo().HasAttribute(SpellAttr5.RemoveEnteringArena); // special marker, always remove
|
||||||
|
|||||||
@@ -2440,7 +2440,7 @@ namespace Game.Entities
|
|||||||
// interrupting auras with SpellAuraInterruptFlags.Damage before checking !damage (absorbed damage breaks that type of auras)
|
// interrupting auras with SpellAuraInterruptFlags.Damage before checking !damage (absorbed damage breaks that type of auras)
|
||||||
if (spellProto != null)
|
if (spellProto != null)
|
||||||
{
|
{
|
||||||
if (!spellProto.HasAttribute(SpellAttr4.DamageDoesntBreakAuras))
|
if (!spellProto.HasAttribute(SpellAttr4.ReactiveDamageProc))
|
||||||
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto);
|
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2657,7 +2657,7 @@ namespace Game.Entities
|
|||||||
if (damagetype != DamageEffectType.DOT && damage > 0 && !victim.GetOwnerGUID().IsPlayer() && (spellProto == null || !spellProto.HasAura(AuraType.DamageShield)))
|
if (damagetype != DamageEffectType.DOT && damage > 0 && !victim.GetOwnerGUID().IsPlayer() && (spellProto == null || !spellProto.HasAura(AuraType.DamageShield)))
|
||||||
victim.ToCreature().SetLastDamagedTime(GameTime.GetGameTime() + SharedConst.MaxAggroResetTime);
|
victim.ToCreature().SetLastDamagedTime(GameTime.GetGameTime() + SharedConst.MaxAggroResetTime);
|
||||||
|
|
||||||
if (attacker != null)
|
if (attacker != null && (spellProto == null || !spellProto.HasAttribute(SpellAttr4.NoHarmfulThreat)))
|
||||||
victim.GetThreatManager().AddThreat(attacker, damage, spellProto);
|
victim.GetThreatManager().AddThreat(attacker, damage, spellProto);
|
||||||
}
|
}
|
||||||
else // victim is a player
|
else // victim is a player
|
||||||
@@ -3245,13 +3245,6 @@ namespace Game.Entities
|
|||||||
if (schoolMask.HasAnyFlag(SpellSchoolMask.Holy) && victim.GetTypeId() != TypeId.Unit)
|
if (schoolMask.HasAnyFlag(SpellSchoolMask.Holy) && victim.GetTypeId() != TypeId.Unit)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Ignore spells that can't be resisted
|
|
||||||
if (spellInfo != null)
|
|
||||||
{
|
|
||||||
if (spellInfo.HasAttribute(SpellAttr4.IgnoreResistances))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float averageResist = CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
|
float averageResist = CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
|
||||||
|
|
||||||
float[] discreteResistProbability = new float[11];
|
float[] discreteResistProbability = new float[11];
|
||||||
|
|||||||
@@ -1828,6 +1828,10 @@ namespace Game.Spells
|
|||||||
if (target.GetGUID() != GetCasterGUID())
|
if (target.GetGUID() != GetCasterGUID())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!m_spellInfo.HasAttribute(SpellAttr4.AllowProcWhileSitting))
|
||||||
|
if (!target.IsStandState())
|
||||||
|
return 0;
|
||||||
|
|
||||||
bool success = RandomHelper.randChance(CalcProcChance(procEntry, eventInfo));
|
bool success = RandomHelper.randChance(CalcProcChance(procEntry, eventInfo));
|
||||||
|
|
||||||
SetLastProcAttemptTime(now);
|
SetLastProcAttemptTime(now);
|
||||||
|
|||||||
@@ -5023,14 +5023,14 @@ namespace Game.Spells
|
|||||||
damage = damageReducedArmor;
|
damage = damageReducedArmor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage))
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.IgnoreDamageTakenModifiers))
|
||||||
{
|
{
|
||||||
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura))
|
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura))
|
||||||
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, GetBase().GetCastItemGUID());
|
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, GetBase().GetCastItemGUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
int dmg = (int)damage;
|
int dmg = (int)damage;
|
||||||
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage) && caster != null && caster.CanApplyResilience())
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.IgnoreDamageTakenModifiers) && caster != null && caster.CanApplyResilience())
|
||||||
Unit.ApplyResilience(target, ref dmg);
|
Unit.ApplyResilience(target, ref dmg);
|
||||||
damage = (uint)dmg;
|
damage = (uint)dmg;
|
||||||
|
|
||||||
@@ -5105,14 +5105,14 @@ namespace Game.Spells
|
|||||||
damage = damageReducedArmor;
|
damage = damageReducedArmor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage))
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.IgnoreDamageTakenModifiers))
|
||||||
{
|
{
|
||||||
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura))
|
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura))
|
||||||
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, GetBase().GetCastItemGUID());
|
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, GetBase().GetCastItemGUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
int dmg = (int)damage;
|
int dmg = (int)damage;
|
||||||
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage) && caster != null && caster.CanApplyResilience())
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.IgnoreDamageTakenModifiers) && caster != null && caster.CanApplyResilience())
|
||||||
Unit.ApplyResilience(target, ref dmg);
|
Unit.ApplyResilience(target, ref dmg);
|
||||||
|
|
||||||
damage = (uint)dmg;
|
damage = (uint)dmg;
|
||||||
@@ -5284,7 +5284,8 @@ namespace Game.Spells
|
|||||||
{
|
{
|
||||||
gainedAmount = caster.ModifyPower(powerType, gainAmount);
|
gainedAmount = caster.ModifyPower(powerType, gainAmount);
|
||||||
// energize is not modified by threat modifiers
|
// energize is not modified by threat modifiers
|
||||||
target.GetThreatManager().AddThreat(caster, gainedAmount * 0.5f, GetSpellInfo(), true);
|
if (!GetSpellInfo().HasAttribute(SpellAttr4.NoHelpfulThreat))
|
||||||
|
target.GetThreatManager().AddThreat(caster, gainedAmount * 0.5f, GetSpellInfo(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drain Mana
|
// Drain Mana
|
||||||
|
|||||||
+90
-45
@@ -99,7 +99,7 @@ namespace Game.Spells
|
|||||||
if (info.HasAttribute(SpellAttr2.DoNotReportSpellFailure))
|
if (info.HasAttribute(SpellAttr2.DoNotReportSpellFailure))
|
||||||
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.DontReportCastError;
|
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.DontReportCastError;
|
||||||
|
|
||||||
if (m_spellInfo.HasAttribute(SpellAttr4.CanCastWhileCasting))
|
if (m_spellInfo.HasAttribute(SpellAttr4.AllowCastWhileCasting))
|
||||||
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.IgnoreCastInProgress;
|
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.IgnoreCastInProgress;
|
||||||
|
|
||||||
effectHandleMode = SpellEffectHandleMode.Launch;
|
effectHandleMode = SpellEffectHandleMode.Launch;
|
||||||
@@ -529,6 +529,9 @@ namespace Game.Spells
|
|||||||
if (target)
|
if (target)
|
||||||
{
|
{
|
||||||
SpellDestination dest = new(target);
|
SpellDestination dest = new(target);
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
m_targets.SetDst(dest);
|
m_targets.SetDst(dest);
|
||||||
}
|
}
|
||||||
@@ -541,6 +544,9 @@ namespace Game.Spells
|
|||||||
case Targets.DestChannelCaster:
|
case Targets.DestChannelCaster:
|
||||||
{
|
{
|
||||||
SpellDestination dest = new(channeledSpell.GetCaster());
|
SpellDestination dest = new(channeledSpell.GetCaster());
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
m_targets.SetDst(dest);
|
m_targets.SetDst(dest);
|
||||||
break;
|
break;
|
||||||
@@ -607,6 +613,9 @@ namespace Game.Spells
|
|||||||
if (focusObject != null)
|
if (focusObject != null)
|
||||||
{
|
{
|
||||||
SpellDestination dest = new(focusObject);
|
SpellDestination dest = new(focusObject);
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
m_targets.SetDst(dest);
|
m_targets.SetDst(dest);
|
||||||
}
|
}
|
||||||
@@ -681,6 +690,9 @@ namespace Game.Spells
|
|||||||
break;
|
break;
|
||||||
case SpellTargetObjectTypes.Dest:
|
case SpellTargetObjectTypes.Dest:
|
||||||
SpellDestination dest = new(target);
|
SpellDestination dest = new(target);
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
m_targets.SetDst(dest);
|
m_targets.SetDst(dest);
|
||||||
break;
|
break;
|
||||||
@@ -849,6 +861,8 @@ namespace Game.Spells
|
|||||||
if (targetType.GetObjectType() == SpellTargetObjectTypes.UnitAndDest)
|
if (targetType.GetObjectType() == SpellTargetObjectTypes.UnitAndDest)
|
||||||
{
|
{
|
||||||
SpellDestination dest = new(referer);
|
SpellDestination dest = new(referer);
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
|
|
||||||
@@ -1064,6 +1078,10 @@ namespace Game.Spells
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
m_targets.SetDst(dest);
|
m_targets.SetDst(dest);
|
||||||
}
|
}
|
||||||
@@ -1095,6 +1113,9 @@ namespace Game.Spells
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
m_targets.SetDst(dest);
|
m_targets.SetDst(dest);
|
||||||
}
|
}
|
||||||
@@ -1134,6 +1155,9 @@ namespace Game.Spells
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
m_targets.ModDst(dest);
|
m_targets.ModDst(dest);
|
||||||
}
|
}
|
||||||
@@ -1255,16 +1279,21 @@ namespace Game.Spells
|
|||||||
m_applyMultiplierMask |= effMask;
|
m_applyMultiplierMask |= effMask;
|
||||||
|
|
||||||
List<WorldObject> targets = new();
|
List<WorldObject> targets = new();
|
||||||
SearchChainTargets(targets, (uint)maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions, targetType.GetTarget() == Targets.UnitChainhealAlly);
|
SearchChainTargets(targets, (uint)maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo, targetType.GetTarget() == Targets.UnitChainhealAlly);
|
||||||
|
|
||||||
// Chain primary target is added earlier
|
// Chain primary target is added earlier
|
||||||
CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
|
CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
|
||||||
|
|
||||||
|
Position losPosition = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target;
|
||||||
|
|
||||||
foreach (var obj in targets)
|
foreach (var obj in targets)
|
||||||
{
|
{
|
||||||
Unit unitTarget = obj.ToUnit();
|
Unit unitTarget = obj.ToUnit();
|
||||||
if (unitTarget)
|
if (unitTarget)
|
||||||
AddUnitTarget(unitTarget, effMask, false);
|
AddUnitTarget(unitTarget, effMask, false, true, losPosition);
|
||||||
|
|
||||||
|
if (!m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) && !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.ChainFromInitialTarget))
|
||||||
|
losPosition = obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1360,6 +1389,9 @@ namespace Game.Spells
|
|||||||
float z = m_targets.GetSrcPos().posZ + bestDist * (a * bestDist + b);
|
float z = m_targets.GetSrcPos().posZ + bestDist * (a * bestDist + b);
|
||||||
|
|
||||||
SpellDestination dest = new(x, y, z, unitCaster.GetOrientation());
|
SpellDestination dest = new(x, y, z, unitCaster.GetOrientation());
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.UseFacingFromSpell))
|
||||||
|
dest.Position.SetOrientation(spellEffectInfo.PositionFacing);
|
||||||
|
|
||||||
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
CallScriptDestinationTargetSelectHandlers(ref dest, spellEffectInfo.EffectIndex, targetType);
|
||||||
m_targets.ModDst(dest);
|
m_targets.ModDst(dest);
|
||||||
}
|
}
|
||||||
@@ -1615,7 +1647,7 @@ namespace Game.Spells
|
|||||||
SearchTargets(searcher, containerTypeMask, m_caster, position, range);
|
SearchTargets(searcher, containerTypeMask, m_caster, position, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchChainTargets(List<WorldObject> targets, uint chainTargets, WorldObject target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, List<Condition> condList, bool isChainHeal)
|
void SearchChainTargets(List<WorldObject> targets, uint chainTargets, WorldObject target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellEffectInfo spellEffectInfo, bool isChainHeal)
|
||||||
{
|
{
|
||||||
// max dist for jump target selection
|
// max dist for jump target selection
|
||||||
float jumpRadius = 0.0f;
|
float jumpRadius = 0.0f;
|
||||||
@@ -1644,32 +1676,23 @@ namespace Game.Spells
|
|||||||
if (modOwner)
|
if (modOwner)
|
||||||
modOwner.ApplySpellMod(m_spellInfo, SpellModOp.ChainJumpDistance, ref jumpRadius, this);
|
modOwner.ApplySpellMod(m_spellInfo, SpellModOp.ChainJumpDistance, ref jumpRadius, this);
|
||||||
|
|
||||||
// chain lightning/heal spells and similar - allow to jump at larger distance and go out of los
|
float searchRadius;
|
||||||
bool isBouncingFar = (m_spellInfo.HasAttribute(SpellAttr4.AreaTargetChain)
|
if (m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster))
|
||||||
|| m_spellInfo.DmgClass == SpellDmgClass.None
|
searchRadius = GetMinMaxRange(false).maxRange;
|
||||||
|| m_spellInfo.DmgClass == SpellDmgClass.Magic);
|
else if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.ChainFromInitialTarget))
|
||||||
|
searchRadius= jumpRadius;
|
||||||
// max dist which spell can reach
|
else
|
||||||
float searchRadius = jumpRadius;
|
searchRadius= jumpRadius * chainTargets;
|
||||||
if (isBouncingFar)
|
|
||||||
searchRadius *= chainTargets;
|
|
||||||
|
|
||||||
WorldObject chainSource = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target;
|
WorldObject chainSource = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target;
|
||||||
List<WorldObject> tempTargets = new();
|
List<WorldObject> tempTargets = new();
|
||||||
SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, condList);
|
SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions);
|
||||||
tempTargets.Remove(target);
|
tempTargets.Remove(target);
|
||||||
|
|
||||||
// remove targets which are always invalid for chain spells
|
// remove targets which are always invalid for chain spells
|
||||||
// for some spells allow only chain targets in front of caster (swipe for example)
|
// for some spells allow only chain targets in front of caster (swipe for example)
|
||||||
if (!isBouncingFar)
|
if (m_spellInfo.HasAttribute(SpellAttr5.MeleeChainTargeting))
|
||||||
{
|
tempTargets.RemoveAll(obj => !m_caster.HasInArc(MathF.PI, obj));
|
||||||
for (var i = 0; i < tempTargets.Count; ++i)
|
|
||||||
{
|
|
||||||
var obj = tempTargets[i];
|
|
||||||
if (!m_caster.HasInArc(MathFunctions.PI, obj))
|
|
||||||
tempTargets.Remove(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (chainTargets != 0)
|
while (chainTargets != 0)
|
||||||
{
|
{
|
||||||
@@ -1700,7 +1723,7 @@ namespace Game.Spells
|
|||||||
{
|
{
|
||||||
if (found == null)
|
if (found == null)
|
||||||
{
|
{
|
||||||
if ((!isBouncingFar || chainSource.IsWithinDist(obj, jumpRadius)) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
|
if (chainSource.IsWithinDist(obj, jumpRadius) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
|
||||||
found = obj;
|
found = obj;
|
||||||
}
|
}
|
||||||
else if (chainSource.GetDistanceOrder(obj, found) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
|
else if (chainSource.GetDistanceOrder(obj, found) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
|
||||||
@@ -1711,7 +1734,7 @@ namespace Game.Spells
|
|||||||
if (found == null)
|
if (found == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster))
|
if (!m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) && !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes.ChainFromInitialTarget))
|
||||||
chainSource = found;
|
chainSource = found;
|
||||||
|
|
||||||
targets.Add(found);
|
targets.Add(found);
|
||||||
@@ -1829,17 +1852,33 @@ namespace Game.Spells
|
|||||||
if (m_caster != target)
|
if (m_caster != target)
|
||||||
{
|
{
|
||||||
float hitDelay = m_spellInfo.LaunchDelay;
|
float hitDelay = m_spellInfo.LaunchDelay;
|
||||||
|
WorldObject missileSource = m_caster;
|
||||||
|
if (m_spellInfo.HasAttribute(SpellAttr4.BouncyChainMissiles))
|
||||||
|
{
|
||||||
|
var previousTargetInfo = m_UniqueTargetInfo.FindLast(target => (target.EffectMask & effectMask) != 0);
|
||||||
|
if (previousTargetInfo != null)
|
||||||
|
{
|
||||||
|
hitDelay = 0.0f; // this is not the first target in chain, LaunchDelay was already included
|
||||||
|
|
||||||
|
WorldObject previousTarget = Global.ObjAccessor.GetWorldObject(m_caster, previousTargetInfo.TargetGUID);
|
||||||
|
if (previousTarget != null)
|
||||||
|
missileSource = previousTarget;
|
||||||
|
|
||||||
|
targetInfo.TimeDelay += previousTargetInfo.TimeDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
|
if (m_spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
|
||||||
hitDelay += m_spellInfo.Speed;
|
hitDelay += m_spellInfo.Speed;
|
||||||
else if (m_spellInfo.Speed > 0.0f)
|
else if (m_spellInfo.Speed > 0.0f)
|
||||||
{
|
{
|
||||||
// calculate spell incoming interval
|
// calculate spell incoming interval
|
||||||
/// @todo this is a hack
|
/// @todo this is a hack
|
||||||
float dist = Math.Max(m_caster.GetDistance(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ()), 5.0f);
|
float dist = Math.Max(missileSource.GetDistance(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ()), 5.0f);
|
||||||
hitDelay += dist / m_spellInfo.Speed;
|
hitDelay += dist / m_spellInfo.Speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
targetInfo.TimeDelay = (ulong)Math.Floor(hitDelay * 1000.0f);
|
targetInfo.TimeDelay += (ulong)Math.Floor(hitDelay * 1000.0f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
targetInfo.TimeDelay = 0L;
|
targetInfo.TimeDelay = 0L;
|
||||||
@@ -2240,7 +2279,7 @@ namespace Game.Spells
|
|||||||
spellAura = null;
|
spellAura = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DoTriggersOnSpellHit(Unit unit, uint effMask)
|
public void DoTriggersOnSpellHit(Unit unit)
|
||||||
{
|
{
|
||||||
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras
|
// handle SPELL_AURA_ADD_TARGET_TRIGGER auras
|
||||||
// this is executed after spell proc spells on target hit
|
// this is executed after spell proc spells on target hit
|
||||||
@@ -2251,7 +2290,7 @@ namespace Game.Spells
|
|||||||
int _duration = 0;
|
int _duration = 0;
|
||||||
foreach (var hit in m_hitTriggerSpells)
|
foreach (var hit in m_hitTriggerSpells)
|
||||||
{
|
{
|
||||||
if (CanExecuteTriggersOnHit(effMask, hit.triggeredByAura) && RandomHelper.randChance(hit.chance))
|
if (CanExecuteTriggersOnHit(unit, hit.triggeredByAura) && RandomHelper.randChance(hit.chance))
|
||||||
{
|
{
|
||||||
m_caster.CastSpell(unit, hit.triggeredSpell.Id, new CastSpellExtraArgs(TriggerCastFlags.FullMask)
|
m_caster.CastSpell(unit, hit.triggeredSpell.Id, new CastSpellExtraArgs(TriggerCastFlags.FullMask)
|
||||||
.SetTriggeringSpell(this)
|
.SetTriggeringSpell(this)
|
||||||
@@ -2850,7 +2889,7 @@ namespace Game.Spells
|
|||||||
creatureCaster.ReleaseSpellFocus(this);
|
creatureCaster.ReleaseSpellFocus(this);
|
||||||
|
|
||||||
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
|
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
|
||||||
if ((m_spellInfo.HasHitDelay() && !m_spellInfo.IsChanneled()) || m_spellInfo.HasAttribute(SpellAttr4.Unk4))
|
if ((m_spellInfo.HasHitDelay() && !m_spellInfo.IsChanneled()) || m_spellInfo.HasAttribute(SpellAttr4.NoHarmfulThreat))
|
||||||
{
|
{
|
||||||
// Remove used for cast item if need (it can be already NULL after TakeReagents call
|
// Remove used for cast item if need (it can be already NULL after TakeReagents call
|
||||||
// in case delayed spell remove item at cast delay start
|
// in case delayed spell remove item at cast delay start
|
||||||
@@ -5726,7 +5765,10 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if target already has the same type, but more powerful aura
|
// check if target already has the same type, but more powerful aura
|
||||||
if (nonAuraEffectMask == 0 && (approximateAuraEffectMask & (1 << (int)spellEffectInfo.EffectIndex)) != 0 && !m_spellInfo.IsTargetingArea())
|
if (!m_spellInfo.HasAttribute(SpellAttr4.AuraNeverBounces)
|
||||||
|
&& (nonAuraEffectMask == 0 || m_spellInfo.HasAttribute(SpellAttr4.AuraBounceFailsSpell))
|
||||||
|
&& (approximateAuraEffectMask & (1 << (int)spellEffectInfo.EffectIndex)) != 0
|
||||||
|
&& !m_spellInfo.IsTargetingArea())
|
||||||
{
|
{
|
||||||
Unit target = m_targets.GetUnitTarget();
|
Unit target = m_targets.GetUnitTarget();
|
||||||
if (target != null)
|
if (target != null)
|
||||||
@@ -6012,11 +6054,11 @@ namespace Game.Spells
|
|||||||
if (isRatedBattleground && m_spellInfo.HasAttribute(SpellAttr9.UsableInRatedBattlegrounds))
|
if (isRatedBattleground && m_spellInfo.HasAttribute(SpellAttr9.UsableInRatedBattlegrounds))
|
||||||
return SpellCastResult.SpellCastOk;
|
return SpellCastResult.SpellCastOk;
|
||||||
|
|
||||||
if (isArena && m_spellInfo.HasAttribute(SpellAttr4.UsableInArena))
|
if (isArena && m_spellInfo.HasAttribute(SpellAttr4.IgnoreDefaultArenaRestrictions))
|
||||||
return SpellCastResult.SpellCastOk;
|
return SpellCastResult.SpellCastOk;
|
||||||
|
|
||||||
// check NOT_USABLE attributes
|
// check NOT_USABLE attributes
|
||||||
if (m_spellInfo.HasAttribute(SpellAttr4.NotUsableInArenaOrRatedBg))
|
if (m_spellInfo.HasAttribute(SpellAttr4.NotInArenaOrRatedBattleground))
|
||||||
return isArena ? SpellCastResult.NotInArena : SpellCastResult.NotInBattleground;
|
return isArena ? SpellCastResult.NotInArena : SpellCastResult.NotInBattleground;
|
||||||
|
|
||||||
if (isArena && m_spellInfo.HasAttribute(SpellAttr9.NotUsableInArena))
|
if (isArena && m_spellInfo.HasAttribute(SpellAttr9.NotUsableInArena))
|
||||||
@@ -7617,15 +7659,20 @@ namespace Game.Spells
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanExecuteTriggersOnHit(uint effMask, SpellInfo triggeredByAura = null)
|
public bool CanExecuteTriggersOnHit(Unit unit, SpellInfo triggeredByAura = null)
|
||||||
{
|
{
|
||||||
bool only_on_caster = (triggeredByAura != null && triggeredByAura.HasAttribute(SpellAttr4.ProcOnlyOnCaster));
|
bool onlyOnTarget = triggeredByAura != null && triggeredByAura.HasAttribute(SpellAttr4.ClassTriggerOnlyOnTarget);
|
||||||
// If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a casted spell with TARGET_UNIT_CASTER
|
if (!onlyOnTarget)
|
||||||
foreach (var spellEffectInfo in m_spellInfo.GetEffects())
|
return true;
|
||||||
{
|
|
||||||
if ((effMask & (1 << (int)spellEffectInfo.EffectIndex)) != 0 && (!only_on_caster || (spellEffectInfo.TargetA.GetTarget() == Targets.UnitCaster)))
|
// If triggeredByAura has SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET then it can only proc on either noncaster units...
|
||||||
return true;
|
if (unit != m_caster)
|
||||||
}
|
return true;
|
||||||
|
|
||||||
|
// ... or caster if it is the only target
|
||||||
|
if (m_UniqueTargetInfo.Count == 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8278,9 +8325,7 @@ namespace Game.Spells
|
|||||||
ProcFlagsHit hitMask = ProcFlagsHit.None;
|
ProcFlagsHit hitMask = ProcFlagsHit.None;
|
||||||
|
|
||||||
// Spells with this flag cannot trigger if effect is cast on self
|
// Spells with this flag cannot trigger if effect is cast on self
|
||||||
bool canEffectTrigger = (!spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs) || !spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressTargetProcs))
|
bool canEffectTrigger = (!spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs) || !spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressTargetProcs)) && spell.unitTarget.CanProc();
|
||||||
&& spell.unitTarget.CanProc()
|
|
||||||
&& (spell.CanExecuteTriggersOnHit(EffectMask) || MissCondition == SpellMissInfo.Immune || MissCondition == SpellMissInfo.Immune2);
|
|
||||||
|
|
||||||
// Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
|
// Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
|
||||||
if (canEffectTrigger && !procAttacker && !procVictim)
|
if (canEffectTrigger && !procAttacker && !procVictim)
|
||||||
@@ -8516,7 +8561,7 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
|
// Needs to be called after dealing damage/healing to not remove breaking on damage auras
|
||||||
spell.DoTriggersOnSpellHit(_spellHitTarget, EffectMask);
|
spell.DoTriggersOnSpellHit(_spellHitTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_enablePVP)
|
if (_enablePVP)
|
||||||
|
|||||||
@@ -4347,7 +4347,7 @@ namespace Game.Spells
|
|||||||
if (Convert.ToBoolean(aura.GetSpellInfo().GetDispelMask() & dispelMask))
|
if (Convert.ToBoolean(aura.GetSpellInfo().GetDispelMask() & dispelMask))
|
||||||
{
|
{
|
||||||
// Need check for passive? this
|
// Need check for passive? this
|
||||||
if (!aurApp.IsPositive() || aura.IsPassive() || aura.GetSpellInfo().HasAttribute(SpellAttr4.NotStealable))
|
if (!aurApp.IsPositive() || aura.IsPassive() || aura.GetSpellInfo().HasAttribute(SpellAttr4.CannotBeStolen))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
|
// 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
|
||||||
|
|||||||
@@ -580,7 +580,7 @@ namespace Game.Spells
|
|||||||
|
|
||||||
public bool HasInitialAggro()
|
public bool HasInitialAggro()
|
||||||
{
|
{
|
||||||
return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr2.NoInitialThreat));
|
return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr2.NoInitialThreat) || HasAttribute(SpellAttr4.NoHarmfulThreat));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasHitDelay()
|
public bool HasHitDelay()
|
||||||
@@ -858,7 +858,7 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
|
|
||||||
// continent limitation (virtual continent)
|
// continent limitation (virtual continent)
|
||||||
if (HasAttribute(SpellAttr4.CastOnlyInOutland))
|
if (HasAttribute(SpellAttr4.OnlyFlyingAreas))
|
||||||
{
|
{
|
||||||
uint mountFlags = 0;
|
uint mountFlags = 0;
|
||||||
if (player && player.HasAuraType(AuraType.MountRestrictions))
|
if (player && player.HasAuraType(AuraType.MountRestrictions))
|
||||||
@@ -2859,7 +2859,7 @@ namespace Game.Spells
|
|||||||
bool initiallyNegative = powerCost < 0;
|
bool initiallyNegative = powerCost < 0;
|
||||||
|
|
||||||
// Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
|
// Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
|
||||||
if (HasAttribute(SpellAttr4.SpellVsExtendCost))
|
if (HasAttribute(SpellAttr4.WeaponSpeedCostScaling))
|
||||||
{
|
{
|
||||||
uint speed = 0;
|
uint speed = 0;
|
||||||
SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(unitCaster.GetShapeshiftForm());
|
SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(unitCaster.GetShapeshiftForm());
|
||||||
@@ -3323,6 +3323,9 @@ namespace Game.Spells
|
|||||||
if (spellInfo.HasAttribute(SpellAttr0.AuraIsDebuff))
|
if (spellInfo.HasAttribute(SpellAttr0.AuraIsDebuff))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (spellInfo.HasAttribute(SpellAttr4.AuraIsBuff))
|
||||||
|
return true;
|
||||||
|
|
||||||
visited.Add(Tuple.Create(spellInfo, effect.EffectIndex));
|
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
|
//We need scaling level info for some auras that compute bp 0 or positive but should be debuffs
|
||||||
|
|||||||
@@ -3156,7 +3156,7 @@ namespace Game.Entities
|
|||||||
60864 // Jaws of Death
|
60864 // Jaws of Death
|
||||||
}, spellInfo =>
|
}, spellInfo =>
|
||||||
{
|
{
|
||||||
spellInfo.AttributesEx4 |= SpellAttr4.FixedDamage;
|
spellInfo.AttributesEx4 |= SpellAttr4.IgnoreDamageTakenModifiers;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Howl of Azgalor
|
// Howl of Azgalor
|
||||||
@@ -3824,12 +3824,6 @@ namespace Game.Entities
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Coldflame (Lord Marrowgar)
|
|
||||||
ApplySpellFix(new[] { 69146 }, spellInfo =>
|
|
||||||
{
|
|
||||||
spellInfo.AttributesEx4 &= ~SpellAttr4.IgnoreResistances;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Shadow's Fate
|
// Shadow's Fate
|
||||||
ApplySpellFix(new[] { 71169 }, spellInfo =>
|
ApplySpellFix(new[] { 71169 }, spellInfo =>
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user