Core/Spells: Rename SpellAttr2 to use official attribute names

Port From (https://github.com/TrinityCore/TrinityCore/commit/dda375b9868d6dbe2a4d58b386bb90ae41d25e0d)
This commit is contained in:
hondacrx
2022-06-01 11:53:42 -04:00
parent a2d9499152
commit a198e03a1d
13 changed files with 256 additions and 157 deletions
+32 -32
View File
@@ -1653,38 +1653,38 @@ namespace Framework.Constants
} }
public enum SpellAttr2 : uint public enum SpellAttr2 : uint
{ {
CanTargetDead = 0x01, // 0 Can Target Dead Unit Or Corpse AllowDeadTarget = 0x01, // Allow Dead Target
Unk1 = 0x02, // 1 Vanish, Shadowform, Ghost Wolf And Other NoShapeshiftUi = 0x02, // No Shapeshift Ui (Client Only) Description Does Not Replace Action Bar When Shapeshifted
CanTargetNotInLos = 0x04, // 2 26368 4.0.1 Dbc Change IgnoreLineOfSight = 0x04, // Ignore Line Of Sight
Unk3 = 0x08, // 3 AllowLowLevelBuff = 0x08, // Allow Low Level Buff
DisplayInStanceBar = 0x10, // 4 Client Displays Icon In Stance Bar When Learned, Even If Not Shapeshift UseShapeshiftBar = 0x10, // Use Shapeshift Bar (Client Only)
AutorepeatFlag = 0x20, // 5 AutoRepeat = 0x20, // Auto Repeat
CantTargetTapped = 0x40, // 6 Target Must Be Tapped By Caster CannotCastOnTapped = 0x40, // Cannot Cast On Tapped Description Can Only Target Untapped Units, Or Those Tapped By Caster
Unk7 = 0x80, // 7 DoNotReportSpellFailure = 0x80, // Do Not Report Spell Failure
Unk8 = 0x100, // 8 Not Set In 3.0.3 IncludeInAdvancedCombatLog = 0x100, // Include In Advanced Combat Log (Client Only) Description Determines Whether To Include This Aura In List Of Auras In SmsgEncounterStart
Unk9 = 0x200, // 9 AlwaysCastAsUnit = 0x200, /*Nyi, Unk*/ // Always Cast As Unit
Unk10 = 0x400, // 10 Related To Tame SpecialTamingFlag = 0x400, // Special Taming Flag Description Related To Taming?
HealthFunnel = 0x800, // 11 NoTargetPerSecondCosts = 0x800, // No Target Per-Second Costs
Unk12 = 0x1000, // 12 Cleave, Heart Strike, Maul, Sunder Armor, Swipe ChainFromCaster = 0x1000, // Chain From Caster
PreserveEnchantInArena = 0x2000, // 13 Items Enchanted By Spells With This Flag Preserve The Enchant To Arenas EnchantOwnItemOnly = 0x2000, // Enchant Own Item Only
Unk14 = 0x4000, // 14 AllowWhileInvisible = 0x4000, // Allow While Invisible
Unk15 = 0x8000, // 15 Not Set In 3.0.3 DoNotConsumeIfGainedDuringCast = 0x8000, // Do Not Consume If Gained During Cast
TameBeast = 0x10000, // 16 NoActivePets = 0x10000, // No Active Pets
NotResetAutoActions = 0x20000, // 17 Don'T Reset Timers For Melee Autoattacks (Swings) Or Ranged Autoattacks (Autoshoots) DoNotResetCombatTimers = 0x20000, // Do Not Reset Combat Timers Description Does Not Reset Melee/Ranged Autoattack Timer On Cast
ReqDeadPet = 0x40000, // 18 Only Revive Pet And Heart Of The Pheonix NoJumpWhileCastPending = 0x40000, // No Jump While Cast Pending (Client Only)
NotNeedShapeshift = 0x80000, // 19 Does Not Necessarly Need Shapeshift AllowWhileNotShapeshiftedCasterForm = 0x80000, // Allow While Not Shapeshifted (Caster Form) Description Even If Stances Are Nonzero, Allow Spell To Be Cast Outside Of Shapeshift (Though Not In A Different Shapeshift)
Unk20 = 0x100000, // 20 InitiateCombatPostCastEnablesAutoAttack = 0x100000, // Initiate Combat Post-Cast (Enables Auto-Attack)
DamageReducedShield = 0x200000, // 21 For Ice Blocks, Pala Immunity Buffs, Priest Absorb Shields, But Used Also For Other Spells . Not Sure! FailOnAllTargetsImmune = 0x200000, // Fail On All Targets Immune Description Causes Bg Flags To Be Dropped If Combined With Attr1DispelAurasOnImmunity
Unk22 = 0x400000, // 22 Ambush, Backstab, Cheap Shot, Death Grip, Garrote, Judgements, Mutilate, Pounce, Ravage, Shiv, Shred NoInitialThreat = 0x400000, // No Initial Threat
IsArcaneConcentration = 0x800000, // 23 Only Mage Arcane Concentration Have This Flag ProcCooldownOnFailure = 0x800000, // Proc Cooldown On Failure
Unk24 = 0x1000000, // 24 ItemCastWithOwnerSkill = 0x1000000, // Item Cast With Owner Skill
Unk25 = 0x2000000, // 25 DontBlockManaRegen = 0x2000000, // Don'T Block Mana Regen
UnaffectedByAuraSchoolImmune = 0x4000000, // 26 Unaffected By School Immunity NoSchoolImmunities = 0x4000000, // No School Immunities Description Allow Aura To Be Applied Despite Target Being Immune To New Aura Applications
Unk27 = 0x8000000, // 27 IgnoreWeaponskill = 0x8000000, // Ignore Weaponskill
IgnoreActionAuraInterruptFlags = 0x10000000, // 28 doesnt break auras with SpellAuraInterruptFlags::Action and SpellAuraInterruptFlags::ActionDelayed NotAnAction = 0x10000000, // Not An Action
CantCrit = 0x20000000, // 29 Spell Can'T Crit CantCrit = 0x20000000, // Can'T Crit
ActiveThreat = 0x40000000, // 30 Active Threat ActiveThreat = 0x40000000, // Active Threat
FoodBuff = 0x80000000 // 31 Food Or Drink Buff (Like Well Fed) RetainItemCast = 0x80000000 // Retain Item Cast Description Passes MCastitem To Triggered Spells
} }
public enum SpellAttr3 : uint public enum SpellAttr3 : uint
{ {
+14 -2
View File
@@ -1917,7 +1917,7 @@ namespace Game.Entities
if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) && if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) &&
((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature())) ((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature()))
castTime = unitCaster.CanInstantCast() ? 0 : (int)(castTime * unitCaster.m_unitData.ModCastingSpeed); castTime = unitCaster.CanInstantCast() ? 0 : (int)(castTime * unitCaster.m_unitData.ModCastingSpeed);
else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutoRepeat))
castTime = (int)(castTime * unitCaster.m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]); castTime = (int)(castTime * unitCaster.m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]);
else if (Global.SpellMgr.IsPartOfSkillLine(SkillType.Cooking, spellInfo.Id) && unitCaster.HasAura(67556)) // cooking with Chef Hat. else if (Global.SpellMgr.IsPartOfSkillLine(SkillType.Cooking, spellInfo.Id) && unitCaster.HasAura(67556)) // cooking with Chef Hat.
castTime = 500; castTime = 500;
@@ -1943,7 +1943,7 @@ namespace Game.Entities
if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) && if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) &&
((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature())) ((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature()))
duration = (int)(duration * unitCaster.m_unitData.ModCastingSpeed); duration = (int)(duration * unitCaster.m_unitData.ModCastingSpeed);
else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutoRepeat))
duration = (int)(duration * unitCaster.m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]); duration = (int)(duration * unitCaster.m_modAttackSpeedPct[(int)WeaponAttackType.RangedAttack]);
} }
@@ -2369,6 +2369,18 @@ namespace Game.Entities
if (args.OriginalCastItemLevel.HasValue) if (args.OriginalCastItemLevel.HasValue)
spell.m_castItemLevel = args.OriginalCastItemLevel.Value; spell.m_castItemLevel = args.OriginalCastItemLevel.Value;
if (spell.m_CastItem == null && info.HasAttribute(SpellAttr2.RetainItemCast))
{
if (args.TriggeringSpell)
spell.m_CastItem = args.TriggeringSpell.m_CastItem;
else if (args.TriggeringAura != null && !args.TriggeringAura.GetBase().GetCastItemGUID().IsEmpty())
{
Player triggeringAuraCaster = args.TriggeringAura.GetCaster()?.ToPlayer();
if (triggeringAuraCaster != null)
spell.m_CastItem = triggeringAuraCaster.GetItemByGuid(args.TriggeringAura.GetBase().GetCastItemGUID());
}
}
return spell.Prepare(targets.Targets, args.TriggeringAura); return spell.Prepare(targets.Targets, args.TriggeringAura);
} }
+1 -1
View File
@@ -3921,7 +3921,7 @@ namespace Game.Entities
Aura itemAura = GetAura((uint)effectData.SpellID, GetGUID(), pItem.GetGUID()); Aura itemAura = GetAura((uint)effectData.SpellID, GetGUID(), pItem.GetGUID());
if (itemAura != null) if (itemAura != null)
itemAura.AddProcCooldown(now + TimeSpan.FromMilliseconds(procEntry.Cooldown)); itemAura.AddProcCooldown(procEntry, now);
continue; continue;
} }
+2 -2
View File
@@ -1261,7 +1261,7 @@ namespace Game.Entities
uint SkillValue = GetPureSkillValue((SkillType)_spell_idx.SkillupSkillLineID); uint SkillValue = GetPureSkillValue((SkillType)_spell_idx.SkillupSkillLineID);
// Alchemy Discoveries here // Alchemy Discoveries here
if (spellInfo != null && spellInfo.Mechanic == Mechanics.Discovery) if (spellInfo.Mechanic == Mechanics.Discovery)
{ {
uint discoveredSpell = SkillDiscovery.GetSkillDiscoverySpell(_spell_idx.SkillupSkillLineID, spellInfo.Id, this); uint discoveredSpell = SkillDiscovery.GetSkillDiscoverySpell(_spell_idx.SkillupSkillLineID, spellInfo.Id, this);
if (discoveredSpell != 0) if (discoveredSpell != 0)
@@ -2277,7 +2277,7 @@ namespace Game.Entities
// talent dependent passives activated at form apply have proper stance data // talent dependent passives activated at form apply have proper stance data
ShapeShiftForm form = GetShapeshiftForm(); ShapeShiftForm form = GetShapeshiftForm();
bool need_cast = (spellInfo.Stances == 0 || (form != 0 && Convert.ToBoolean(spellInfo.Stances & (1ul << ((int)form - 1)))) || bool need_cast = (spellInfo.Stances == 0 || (form != 0 && Convert.ToBoolean(spellInfo.Stances & (1ul << ((int)form - 1)))) ||
(form == 0 && spellInfo.HasAttribute(SpellAttr2.NotNeedShapeshift))); (form == 0 && spellInfo.HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm)));
// Check EquippedItemClass // Check EquippedItemClass
// passive spells which apply aura and have an item requirement are to be added manually, instead of casted // passive spells which apply aura and have an item requirement are to be added manually, instead of casted
+68 -35
View File
@@ -1343,7 +1343,7 @@ namespace Game.Entities
return true; return true;
} }
if (!spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (!spellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
{ {
// Check for immune to application of harmful magical effects // Check for immune to application of harmful magical effects
var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool); var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool);
@@ -1382,7 +1382,7 @@ namespace Game.Entities
if (spellInfo.HasAttribute(SpellAttr0.NoImmunities) && spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) if (spellInfo.HasAttribute(SpellAttr0.NoImmunities) && spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult))
return false; return false;
if (spellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (spellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || spellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
return false; return false;
uint schoolMask = (uint)spellInfo.GetSchoolMask(); uint schoolMask = (uint)spellInfo.GetSchoolMask();
@@ -1422,7 +1422,7 @@ namespace Game.Entities
return false; return false;
} }
public static void ProcSkillsAndAuras(Unit actor, Unit actionTarget, ProcFlagsInit typeMaskActor, ProcFlagsInit typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo) public static void ProcSkillsAndAuras(Unit actor, Unit actionTarget, ProcFlagsInit typeMaskActor, ProcFlagsInit typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo)
{ {
WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack; WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack;
@@ -1482,32 +1482,49 @@ namespace Game.Entities
{ {
DateTime now = GameTime.Now(); DateTime now = GameTime.Now();
void processAuraApplication(AuraApplication aurApp)
{
uint procEffectMask = aurApp.GetBase().GetProcEffectMask(aurApp, eventInfo, now);
if (procEffectMask != 0)
{
aurApp.GetBase().PrepareProcToTrigger(aurApp, eventInfo, now);
aurasTriggeringProc.Add(Tuple.Create(procEffectMask, aurApp));
}
else
{
if (aurApp.GetBase().GetSpellInfo().HasAttribute(SpellAttr0.ProcFailureBurnsCharge))
{
SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(aurApp.GetBase().GetSpellInfo());
if (procEntry != null)
{
aurApp.GetBase().PrepareProcChargeDrop(procEntry, eventInfo);
aurApp.GetBase().ConsumeProcCharges(procEntry);
}
}
if (aurApp.GetBase().GetSpellInfo().HasAttribute(SpellAttr2.ProcCooldownOnFailure))
{
SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(aurApp.GetBase().GetSpellInfo());
if (procEntry != null)
aurApp.GetBase().AddProcCooldown(procEntry, now);
}
}
}
// use provided list of auras which can proc // use provided list of auras which can proc
if (procAuras != null) if (procAuras != null)
{ {
foreach (AuraApplication aurApp in procAuras) foreach (AuraApplication aurApp in procAuras)
{ {
Cypher.Assert(aurApp.GetTarget() == this); Cypher.Assert(aurApp.GetTarget() == this);
uint procEffectMask = aurApp.GetBase().GetProcEffectMask(aurApp, eventInfo, now); processAuraApplication(aurApp);
if (procEffectMask != 0)
{
aurApp.GetBase().PrepareProcToTrigger(aurApp, eventInfo, now);
aurasTriggeringProc.Add(Tuple.Create(procEffectMask, aurApp));
}
} }
} }
// or generate one on our own // or generate one on our own
else else
{ {
foreach (var pair in GetAppliedAuras()) foreach (var pair in GetAppliedAuras())
{ processAuraApplication(pair.Value);
uint procEffectMask = pair.Value.GetBase().GetProcEffectMask(pair.Value, eventInfo, now);
if (procEffectMask != 0)
{
pair.Value.GetBase().PrepareProcToTrigger(pair.Value, eventInfo, now);
aurasTriggeringProc.Add(Tuple.Create(procEffectMask, pair.Value));
}
}
} }
} }
@@ -1556,11 +1573,8 @@ namespace Game.Entities
if (disableProcs) if (disableProcs)
SetCantProc(true); SetCantProc(true);
foreach (var aurAppProc in aurasTriggeringProc) foreach (var (procEffectMask, aurApp) in aurasTriggeringProc)
{ {
AuraApplication aurApp = aurAppProc.Item2;
uint procEffectMask = aurAppProc.Item1;
if (aurApp.GetRemoveMode() != 0) if (aurApp.GetRemoveMode() != 0)
continue; continue;
@@ -1694,7 +1708,7 @@ namespace Game.Entities
{ {
if (!skipInstant || currentSpell.GetCastTime() != 0) if (!skipInstant || currentSpell.GetCastTime() != 0)
{ {
if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers))
return true; return true;
} }
} }
@@ -1703,7 +1717,7 @@ namespace Game.Entities
if (!skipChanneled && currentSpell && if (!skipChanneled && currentSpell &&
(currentSpell.GetState() != SpellState.Finished)) (currentSpell.GetState() != SpellState.Finished))
{ {
if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers))
return true; return true;
} }
currentSpell = GetCurrentSpell(CurrentSpellTypes.AutoRepeat); currentSpell = GetCurrentSpell(CurrentSpellTypes.AutoRepeat);
@@ -2494,7 +2508,7 @@ namespace Game.Entities
if (spellInfo == null) if (spellInfo == null)
return null; return null;
if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.CanTargetDead)) if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.AllowDeadTarget))
return null; return null;
if (target.IsImmunedToSpell(spellInfo, this)) if (target.IsImmunedToSpell(spellInfo, this))
@@ -2823,16 +2837,35 @@ namespace Game.Entities
return dispelList; return dispelList;
} }
bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit unit, SpellInfo spellInfo) bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit unit, SpellInfo auraSpellInfo, SpellInfo interruptSource)
{ {
return flag == SpellAuraInterruptFlags.Moving && unit.CanCastSpellWhileMoving(spellInfo); switch (flag)
{
case SpellAuraInterruptFlags.Moving:
return unit.CanCastSpellWhileMoving(auraSpellInfo);
case SpellAuraInterruptFlags.Action:
case SpellAuraInterruptFlags.ActionDelayed:
if (interruptSource != null)
{
if (interruptSource.HasAttribute(SpellAttr1.AllowWhileStealthed) && auraSpellInfo.HasAura(AuraType.ModStealth))
return true;
if (interruptSource.HasAttribute(SpellAttr2.AllowWhileInvisible) && auraSpellInfo.HasAura(AuraType.ModInvisibility))
return true;
}
break;
default:
break;
}
return false;
} }
bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags2 flag, Unit unit, SpellInfo spellInfo) bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags2 flag, Unit unit, SpellInfo auraSpellInfo, SpellInfo interruptSource)
{ {
return false; return false;
} }
public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint except = 0) public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, SpellInfo source = null)
{ {
if (!HasInterruptFlag(flag)) if (!HasInterruptFlag(flag))
return; return;
@@ -2842,7 +2875,7 @@ namespace Game.Entities
{ {
Aura aura = m_interruptableAuras[i].GetBase(); Aura aura = m_interruptableAuras[i].GetBase();
if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (except == 0 || aura.GetId() != except) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo())) if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (source == null || aura.GetId() != source.Id) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo(), source))
{ {
uint removedAuras = m_removedAurasCount; uint removedAuras = m_removedAurasCount;
RemoveAura(aura, AuraRemoveMode.Interrupt); RemoveAura(aura, AuraRemoveMode.Interrupt);
@@ -2857,15 +2890,15 @@ namespace Game.Entities
{ {
if (spell.GetState() == SpellState.Casting if (spell.GetState() == SpellState.Casting
&& spell.GetSpellInfo().HasChannelInterruptFlag(flag) && spell.GetSpellInfo().HasChannelInterruptFlag(flag)
&& spell.GetSpellInfo().Id != except && (source == null || spell.GetSpellInfo().Id != source.Id)
&& !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo())) && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo(), source))
InterruptNonMeleeSpells(false); InterruptNonMeleeSpells(false);
} }
UpdateInterruptMask(); UpdateInterruptMask();
} }
public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, uint except = 0) public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, SpellInfo source = null)
{ {
if (!HasInterruptFlag(flag)) if (!HasInterruptFlag(flag))
return; return;
@@ -2875,7 +2908,7 @@ namespace Game.Entities
{ {
Aura aura = m_interruptableAuras[i].GetBase(); Aura aura = m_interruptableAuras[i].GetBase();
if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (except == 0 || aura.GetId() != except) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo())) if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (source == null || aura.GetId() != source.Id) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo(), source))
{ {
uint removedAuras = m_removedAurasCount; uint removedAuras = m_removedAurasCount;
RemoveAura(aura, AuraRemoveMode.Interrupt); RemoveAura(aura, AuraRemoveMode.Interrupt);
@@ -2890,8 +2923,8 @@ namespace Game.Entities
{ {
if (spell.GetState() == SpellState.Casting if (spell.GetState() == SpellState.Casting
&& spell.GetSpellInfo().HasChannelInterruptFlag(flag) && spell.GetSpellInfo().HasChannelInterruptFlag(flag)
&& spell.GetSpellInfo().Id != except && (source == null || spell.GetSpellInfo().Id != source.Id)
&& !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo())) && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo(), source))
InterruptNonMeleeSpells(false); InterruptNonMeleeSpells(false);
} }
+3 -3
View File
@@ -2441,10 +2441,10 @@ namespace Game.Entities
if (spellProto != null) if (spellProto != null)
{ {
if (!spellProto.HasAttribute(SpellAttr4.DamageDoesntBreakAuras)) if (!spellProto.HasAttribute(SpellAttr4.DamageDoesntBreakAuras))
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto.Id); victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto);
} }
else else
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, 0); victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage);
if (damage == 0 && damagetype != DamageEffectType.DOT && cleanDamage != null && cleanDamage.absorbed_damage != 0) if (damage == 0 && damagetype != DamageEffectType.DOT && cleanDamage != null && cleanDamage.absorbed_damage != 0)
{ {
@@ -2649,7 +2649,7 @@ namespace Game.Entities
victim.ModifyHealth(-(int)damage); victim.ModifyHealth(-(int)damage);
if (damagetype == DamageEffectType.Direct || damagetype == DamageEffectType.SpellDirect) if (damagetype == DamageEffectType.Direct || damagetype == DamageEffectType.SpellDirect)
victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NonPeriodicDamage, spellProto != null ? spellProto.Id : 0); victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NonPeriodicDamage, spellProto);
if (!victim.IsTypeId(TypeId.Player)) if (!victim.IsTypeId(TypeId.Player))
{ {
+36 -25
View File
@@ -698,7 +698,7 @@ namespace Game.Spells
{ {
if (m_timeCla > diff) if (m_timeCla > diff)
m_timeCla -= (int)diff; m_timeCla -= (int)diff;
else if (caster != null) else if (caster != null && (caster == GetOwner() || !GetSpellInfo().HasAttribute(SpellAttr2.NoTargetPerSecondCosts)))
{ {
if (!m_periodicCosts.Empty()) if (!m_periodicCosts.Empty())
{ {
@@ -1008,7 +1008,7 @@ namespace Game.Spells
{ {
return GetCasterGUID() == target.GetGUID() return GetCasterGUID() == target.GetGUID()
&& m_spellInfo.Stances != 0 && m_spellInfo.Stances != 0
&& !m_spellInfo.HasAttribute(SpellAttr2.NotNeedShapeshift) && !m_spellInfo.HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm)
&& !m_spellInfo.HasAttribute(SpellAttr0.NotShapeshifted); && !m_spellInfo.HasAttribute(SpellAttr0.NotShapeshifted);
} }
@@ -1644,9 +1644,19 @@ namespace Game.Spells
return m_procCooldown > now; return m_procCooldown > now;
} }
public void AddProcCooldown(DateTime cooldownEnd) public void AddProcCooldown(SpellProcEntry procEntry, DateTime now)
{ {
m_procCooldown = cooldownEnd; // cooldowns should be added to the whole aura (see 51698 area aura)
int procCooldown = (int)procEntry.Cooldown;
Unit caster = GetCaster();
if (caster != null)
{
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(GetSpellInfo(), SpellModOp.ProcCooldown, ref procCooldown);
}
m_procCooldown = now + TimeSpan.FromMilliseconds(procCooldown);
} }
public void ResetProcCooldown() public void ResetProcCooldown()
@@ -1663,26 +1673,36 @@ namespace Game.Spells
SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetSpellInfo()); SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetSpellInfo());
Cypher.Assert(procEntry != null); Cypher.Assert(procEntry != null);
PrepareProcChargeDrop(procEntry, eventInfo);
// cooldowns should be added to the whole aura (see 51698 area aura)
AddProcCooldown(procEntry, now);
SetLastProcSuccessTime(now);
}
public void PrepareProcChargeDrop(SpellProcEntry procEntry, ProcEventInfo eventInfo)
{
// take one charge, aura expiration will be handled in Aura.TriggerProcOnEvent (if needed) // take one charge, aura expiration will be handled in Aura.TriggerProcOnEvent (if needed)
if (!procEntry.AttributesMask.HasAnyFlag(ProcAttributes.UseStacksForCharges) && IsUsingCharges() && (eventInfo.GetSpellInfo() == null || !eventInfo.GetSpellInfo().HasAttribute(SpellAttr6.DoNotConsumeResources))) if (!procEntry.AttributesMask.HasAnyFlag(ProcAttributes.UseStacksForCharges) && IsUsingCharges() && (eventInfo.GetSpellInfo() == null || !eventInfo.GetSpellInfo().HasAttribute(SpellAttr6.DoNotConsumeResources)))
{ {
--m_procCharges; --m_procCharges;
SetNeedClientUpdateForTargets(); SetNeedClientUpdateForTargets();
} }
}
// cooldowns should be added to the whole aura (see 51698 area aura) public void ConsumeProcCharges(SpellProcEntry procEntry)
int procCooldown = (int)procEntry.Cooldown; {
Unit caster = GetCaster(); // Remove aura if we've used last charge to proc
if (caster != null) if (procEntry.AttributesMask.HasFlag(ProcAttributes.UseStacksForCharges))
{ {
Player modOwner = caster.GetSpellModOwner(); ModStackAmount(-1);
if (modOwner != null) }
modOwner.ApplySpellMod(GetSpellInfo(), SpellModOp.ProcCooldown, ref procCooldown); else if (IsUsingCharges())
{
if (GetCharges() == 0)
Remove();
} }
AddProcCooldown(now + TimeSpan.FromMilliseconds(procCooldown));
SetLastProcSuccessTime(now);
} }
public uint GetProcEffectMask(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now) public uint GetProcEffectMask(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now)
@@ -1859,16 +1879,7 @@ namespace Game.Spells
CallScriptAfterProcHandlers(aurApp, eventInfo); CallScriptAfterProcHandlers(aurApp, eventInfo);
} }
// Remove aura if we've used last charge to proc ConsumeProcCharges(Global.SpellMgr.GetSpellProcEntry(GetSpellInfo()));
if (Global.SpellMgr.GetSpellProcEntry(m_spellInfo).AttributesMask.HasAnyFlag(ProcAttributes.UseStacksForCharges))
{
ModStackAmount(-1);
}
else if (IsUsingCharges())
{
if (GetCharges() == 0)
Remove();
}
} }
public float CalcPPMProcChance(Unit actor) public float CalcPPMProcChance(Unit actor)
+2 -6
View File
@@ -1308,7 +1308,7 @@ namespace Game.Spells
} }
if (!shapeInfo.Flags.HasAnyFlag(SpellShapeshiftFormFlags.Stance)) if (!shapeInfo.Flags.HasAnyFlag(SpellShapeshiftFormFlags.Stance))
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Shapeshifting, GetId()); target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Shapeshifting, GetSpellInfo());
} }
else else
{ {
@@ -2837,7 +2837,7 @@ namespace Game.Spells
// remove all flag auras (they are positive, but they must be removed when you are immune) // remove all flag auras (they are positive, but they must be removed when you are immune)
if (GetSpellInfo().HasAttribute(SpellAttr1.ImmunityPurgesEffect) if (GetSpellInfo().HasAttribute(SpellAttr1.ImmunityPurgesEffect)
&& GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield)) && GetSpellInfo().HasAttribute(SpellAttr2.FailOnAllTargetsImmune))
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis);
} }
@@ -5206,10 +5206,6 @@ namespace Game.Spells
return; return;
} }
// heal for caster damage (must be alive)
if (target != caster && GetSpellInfo().HasAttribute(SpellAttr2.HealthFunnel) && (caster == null || !caster.IsAlive()))
return;
// don't regen when permanent aura target has full power // don't regen when permanent aura target has full power
if (GetBase().IsPermanent() && target.IsFullHealth()) if (GetBase().IsPermanent() && target.IsFullHealth())
return; return;
+64 -18
View File
@@ -95,6 +95,10 @@ namespace Game.Spells
m_spellState = SpellState.None; m_spellState = SpellState.None;
_triggeredCastFlags = triggerFlags; _triggeredCastFlags = triggerFlags;
if (info.HasAttribute(SpellAttr2.DoNotReportSpellFailure))
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.DontReportCastError;
if (m_spellInfo.HasAttribute(SpellAttr4.CanCastWhileCasting)) if (m_spellInfo.HasAttribute(SpellAttr4.CanCastWhileCasting))
_triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.IgnoreCastInProgress; _triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.IgnoreCastInProgress;
@@ -274,6 +278,35 @@ namespace Game.Spells
if (m_targets.HasDst()) if (m_targets.HasDst())
AddDestTarget(m_targets.GetDst(), spellEffectInfo.EffectIndex); AddDestTarget(m_targets.GetDst(), spellEffectInfo.EffectIndex);
if (spellEffectInfo.TargetA.GetObjectType() == SpellTargetObjectTypes.Unit
|| spellEffectInfo.TargetA.GetObjectType() == SpellTargetObjectTypes.UnitAndDest
|| spellEffectInfo.TargetB.GetObjectType() == SpellTargetObjectTypes.Unit
|| spellEffectInfo.TargetB.GetObjectType() == SpellTargetObjectTypes.UnitAndDest)
{
if (m_spellInfo.HasAttribute(SpellAttr1.RequireAllTargets))
{
bool noTargetFound = !m_UniqueTargetInfo.Any(target => (target.EffectMask & 1 << (int)spellEffectInfo.EffectIndex) != 0);
if (noTargetFound)
{
SendCastResult(m_spellInfo.Id == 51690 ? SpellCastResult.OutOfRange : SpellCastResult.BadTargets);
Finish(false);
return;
}
}
if (m_spellInfo.HasAttribute(SpellAttr2.FailOnAllTargetsImmune))
{
bool anyNonImmuneTargetFound = m_UniqueTargetInfo.Any(target => (target.EffectMask & 1 << (int)spellEffectInfo.EffectIndex) != 0 && target.MissCondition != SpellMissInfo.Immune && target.MissCondition != SpellMissInfo.Immune2);
if (!anyNonImmuneTargetFound)
{
SendCastResult(SpellCastResult.Immune);
Finish(false);
return;
}
}
}
if (m_spellInfo.IsChanneled()) if (m_spellInfo.IsChanneled())
{ {
// maybe do this for all spells? // maybe do this for all spells?
@@ -1621,8 +1654,9 @@ namespace Game.Spells
if (isBouncingFar) if (isBouncingFar)
searchRadius *= chainTargets; searchRadius *= chainTargets;
WorldObject chainSource = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target;
List<WorldObject> tempTargets = new(); List<WorldObject> tempTargets = new();
SearchAreaTargets(tempTargets, searchRadius, target.GetPosition(), m_caster, objectType, selectType, condList); SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, condList);
tempTargets.Remove(target); tempTargets.Remove(target);
// remove targets which are always invalid for chain spells // remove targets which are always invalid for chain spells
@@ -1651,7 +1685,7 @@ namespace Game.Spells
if (unitTarget != null) if (unitTarget != null)
{ {
uint deficit = (uint)(unitTarget.GetMaxHealth() - unitTarget.GetHealth()); uint deficit = (uint)(unitTarget.GetMaxHealth() - unitTarget.GetHealth());
if ((deficit > maxHPDeficit || found == null) && target.IsWithinDist(unitTarget, jumpRadius) && target.IsWithinLOSInMap(unitTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2)) if ((deficit > maxHPDeficit || found == null) && chainSource.IsWithinDist(unitTarget, jumpRadius) && chainSource.IsWithinLOSInMap(unitTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2))
{ {
found = obj; found = obj;
maxHPDeficit = deficit; maxHPDeficit = deficit;
@@ -1666,19 +1700,22 @@ namespace Game.Spells
{ {
if (found == null) if (found == null)
{ {
if ((!isBouncingFar || target.IsWithinDist(obj, jumpRadius)) && target.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2)) if ((!isBouncingFar || chainSource.IsWithinDist(obj, jumpRadius)) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
found = obj; found = obj;
} }
else if (target.GetDistanceOrder(obj, found) && target.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2)) else if (chainSource.GetDistanceOrder(obj, found) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
found = obj; found = obj;
} }
} }
// not found any valid target - chain ends // not found any valid target - chain ends
if (found == null) if (found == null)
break; break;
target = found;
if (!m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster))
chainSource = found;
targets.Add(found);
tempTargets.Remove(found); tempTargets.Remove(found);
targets.Add(target);
--chainTargets; --chainTargets;
} }
} }
@@ -1712,7 +1749,7 @@ namespace Game.Spells
break; break;
case SpellDmgClass.Ranged: case SpellDmgClass.Ranged:
// Auto attack // Auto attack
if (m_spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) if (m_spellInfo.HasAttribute(SpellAttr2.AutoRepeat))
{ {
m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack); m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack);
m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack); m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack);
@@ -1726,7 +1763,7 @@ namespace Game.Spells
default: default:
if (m_spellInfo.EquippedItemClass == ItemClass.Weapon && if (m_spellInfo.EquippedItemClass == ItemClass.Weapon &&
Convert.ToBoolean(m_spellInfo.EquippedItemSubClassMask & (1 << (int)ItemSubClassWeapon.Wand)) Convert.ToBoolean(m_spellInfo.EquippedItemSubClassMask & (1 << (int)ItemSubClassWeapon.Wand))
&& m_spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) // Wands auto attack && m_spellInfo.HasAttribute(SpellAttr2.AutoRepeat)) // Wands auto attack
{ {
m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack); m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack);
m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack); m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack);
@@ -2488,8 +2525,8 @@ namespace Game.Spells
{ {
// stealth must be removed at cast starting (at show channel bar) // stealth must be removed at cast starting (at show channel bar)
// skip triggered spell (item equip spell casting and other not explicit character casts/item uses) // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && m_spellInfo.IsBreakingStealth() && !m_spellInfo.HasAttribute(SpellAttr2.IgnoreActionAuraInterruptFlags)) if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.NotAnAction))
unitCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Action); unitCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Action, m_spellInfo);
// Do not register as current spell when requested to ignore cast in progress // Do not register as current spell when requested to ignore cast in progress
// We don't want to interrupt that other spell with cast time // We don't want to interrupt that other spell with cast time
@@ -2903,8 +2940,8 @@ namespace Game.Spells
if (!hitMask.HasAnyFlag(ProcFlagsHit.Critical)) if (!hitMask.HasAnyFlag(ProcFlagsHit.Critical))
hitMask |= ProcFlagsHit.Normal; hitMask |= ProcFlagsHit.Normal;
if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.IgnoreActionAuraInterruptFlags)) if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.NotAnAction))
m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed); m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed, m_spellInfo);
Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null); Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null);
@@ -3340,7 +3377,7 @@ namespace Game.Spells
if (IsAutoActionResetSpell()) if (IsAutoActionResetSpell())
{ {
if (!m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) if (!m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers))
{ {
unitCaster.ResetAttackTimer(WeaponAttackType.BaseAttack); unitCaster.ResetAttackTimer(WeaponAttackType.BaseAttack);
if (unitCaster.HaveOffhandWeapon()) if (unitCaster.HaveOffhandWeapon())
@@ -4566,7 +4603,7 @@ namespace Game.Spells
if (m_spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) if (m_spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot)
|| m_spellInfo.IsNextMeleeSwingSpell() || m_spellInfo.IsNextMeleeSwingSpell()
|| m_spellInfo.HasAttribute(SpellAttr1.InitiatesCombatEnablesAutoAttack) || m_spellInfo.HasAttribute(SpellAttr1.InitiatesCombatEnablesAutoAttack)
|| m_spellInfo.HasAttribute(SpellAttr2.Unk20) || m_spellInfo.HasAttribute(SpellAttr2.InitiateCombatPostCastEnablesAutoAttack)
|| m_spellInfo.HasEffect(SpellEffectName.Attack) || m_spellInfo.HasEffect(SpellEffectName.Attack)
|| m_spellInfo.HasEffect(SpellEffectName.NormalizedWeaponDmg) || m_spellInfo.HasEffect(SpellEffectName.NormalizedWeaponDmg)
|| m_spellInfo.HasEffect(SpellEffectName.WeaponDamageNoSchool) || m_spellInfo.HasEffect(SpellEffectName.WeaponDamageNoSchool)
@@ -4787,7 +4824,7 @@ namespace Game.Spells
losTarget = dynObj; losTarget = dynObj;
} }
if (!m_spellInfo.HasAttribute(SpellAttr2.CanTargetNotInLos) && !m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS) if (!m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) && !m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS)
&& !unitTarget.IsWithinLOSInMap(losTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2)) && !unitTarget.IsWithinLOSInMap(losTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2))
return SpellCastResult.LineOfSight; return SpellCastResult.LineOfSight;
} }
@@ -4800,7 +4837,7 @@ namespace Game.Spells
float x, y, z; float x, y, z;
m_targets.GetDstPos().GetPosition(out x, out y, out z); m_targets.GetDstPos().GetPosition(out x, out y, out z);
if (!m_spellInfo.HasAttribute(SpellAttr2.CanTargetNotInLos) && !m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS) if (!m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) && !m_spellInfo.HasAttribute(SpellAttr5.AlwaysAoeLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS)
&& !m_caster.IsWithinLOS(x, y, z, LineOfSightChecks.All, ModelIgnoreFlags.M2)) && !m_caster.IsWithinLOS(x, y, z, LineOfSightChecks.All, ModelIgnoreFlags.M2))
return SpellCastResult.LineOfSight; return SpellCastResult.LineOfSight;
} }
@@ -4808,6 +4845,10 @@ namespace Game.Spells
// check pet presence // check pet presence
if (unitCaster != null) if (unitCaster != null)
{ {
if (m_spellInfo.HasAttribute(SpellAttr2.NoActivePets))
if (!unitCaster.GetPetGUID().IsEmpty())
return SpellCastResult.AlreadyHavePet;
foreach (var spellEffectInfo in m_spellInfo.GetEffects()) foreach (var spellEffectInfo in m_spellInfo.GetEffects())
{ {
if (spellEffectInfo.TargetA.GetTarget() == Targets.UnitPet) if (spellEffectInfo.TargetA.GetTarget() == Targets.UnitPet)
@@ -5697,6 +5738,9 @@ namespace Game.Spells
if (m_CastItem != null) if (m_CastItem != null)
return SpellCastResult.ItemEnchantTradeWindow; return SpellCastResult.ItemEnchantTradeWindow;
if (m_spellInfo.HasAttribute(SpellAttr2.EnchantOwnItemOnly))
return SpellCastResult.ItemEnchantTradeWindow;
if (!m_caster.IsTypeId(TypeId.Player)) if (!m_caster.IsTypeId(TypeId.Player))
return SpellCastResult.NotTrading; return SpellCastResult.NotTrading;
@@ -6964,7 +7008,7 @@ namespace Game.Spells
} }
// check for ignore LOS on the effect itself // check for ignore LOS on the effect itself
if (m_spellInfo.HasAttribute(SpellAttr2.CanTargetNotInLos) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS)) if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS))
return true; return true;
// check if gameobject ignores LOS // check if gameobject ignores LOS
@@ -6974,7 +7018,7 @@ namespace Game.Spells
return true; return true;
// if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
if (IsTriggered() && m_triggeredByAuraSpell != null && (m_triggeredByAuraSpell.HasAttribute(SpellAttr2.CanTargetNotInLos) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_triggeredByAuraSpell.Id, null, (byte)DisableFlags.SpellLOS))) if (IsTriggered() && m_triggeredByAuraSpell != null && (m_triggeredByAuraSpell.HasAttribute(SpellAttr2.IgnoreLineOfSight) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_triggeredByAuraSpell.Id, null, (byte)DisableFlags.SpellLOS)))
return true; return true;
// @todo shit below shouldn't be here, but it's temporary // @todo shit below shouldn't be here, but it's temporary
@@ -9052,6 +9096,7 @@ namespace Game.Spells
{ {
public TriggerCastFlags TriggerFlags; public TriggerCastFlags TriggerFlags;
public Item CastItem; public Item CastItem;
public Spell TriggeringSpell;
public AuraEffect TriggeringAura; public AuraEffect TriggeringAura;
public ObjectGuid OriginalCaster = ObjectGuid.Empty; public ObjectGuid OriginalCaster = ObjectGuid.Empty;
public Difficulty CastDifficulty; public Difficulty CastDifficulty;
@@ -9113,6 +9158,7 @@ namespace Game.Spells
public CastSpellExtraArgs SetTriggeringSpell(Spell triggeringSpell) public CastSpellExtraArgs SetTriggeringSpell(Spell triggeringSpell)
{ {
TriggeringSpell = triggeringSpell;
if (triggeringSpell != null) if (triggeringSpell != null)
{ {
OriginalCastItemLevel = triggeringSpell.m_castItemLevel; OriginalCastItemLevel = triggeringSpell.m_castItemLevel;
+17 -9
View File
@@ -305,18 +305,26 @@ namespace Game.Spells
if (effectInfo.Effect == SpellEffectName.TriggerSpell) if (effectInfo.Effect == SpellEffectName.TriggerSpell)
delay = TimeSpan.FromMilliseconds(effectInfo.MiscValue); delay = TimeSpan.FromMilliseconds(effectInfo.MiscValue);
CastSpellExtraArgs args = new(TriggerCastFlags.FullMask);
args.SetOriginalCaster(m_originalCasterGUID);
args.SetTriggeringSpell(this);
// set basepoints for trigger with value effect
if (effectInfo.Effect == SpellEffectName.TriggerSpellWithValue)
for (int i = 0; i < SpellConst.MaxEffects; ++i)
args.AddSpellMod(SpellValueMod.BasePoint0 + i, damage);
m_caster.m_Events.AddEventAtOffset(() => m_caster.m_Events.AddEventAtOffset(() =>
{ {
// original caster guid only for GO cast // original caster guid only for GO cast
m_caster.CastSpell(targets, triggered_spell_id, args); CastSpellExtraArgs args = new(TriggerCastFlags.FullMask);
args.SetOriginalCaster(m_originalCasterGUID);
args.OriginalCastId = m_castId;
args.OriginalCastItemLevel = m_castItemLevel;
if (!m_castItemGUID.IsEmpty() && Global.SpellMgr.GetSpellInfo(effectInfo.TriggerSpell, m_caster.GetMap().GetDifficultyID()).HasAttribute(SpellAttr2.RetainItemCast))
{
Player triggeringAuraCaster = args.TriggeringAura.GetCaster()?.ToPlayer();
if (triggeringAuraCaster != null)
args.CastItem = triggeringAuraCaster.GetItemByGuid(m_castItemGUID);
}
// set basepoints for trigger with value effect
if (effectInfo.Effect == SpellEffectName.TriggerSpellWithValue)
for (int i = 0; i < SpellConst.MaxEffects; ++i)
args.AddSpellMod(SpellValueMod.BasePoint0 + i, damage);
m_caster.CastSpell(targets, effectInfo.TriggerSpell, args);
}, delay); }, delay);
} }
+11 -16
View File
@@ -499,7 +499,7 @@ namespace Game.Spells
public bool IsAllowingDeadTarget() public bool IsAllowingDeadTarget()
{ {
if (HasAttribute(SpellAttr2.CanTargetDead) || Targets.HasAnyFlag(SpellCastTargetFlags.CorpseAlly | SpellCastTargetFlags.CorpseEnemy | SpellCastTargetFlags.UnitDead)) if (HasAttribute(SpellAttr2.AllowDeadTarget) || Targets.HasAnyFlag(SpellCastTargetFlags.CorpseAlly | SpellCastTargetFlags.CorpseEnemy | SpellCastTargetFlags.UnitDead))
return true; return true;
foreach (var effectInfo in _effects) foreach (var effectInfo in _effects)
@@ -566,11 +566,6 @@ namespace Game.Spells
return HasAttribute(SpellAttr0.OnNextSwingNoDamage | SpellAttr0.OnNextSwing); return HasAttribute(SpellAttr0.OnNextSwingNoDamage | SpellAttr0.OnNextSwing);
} }
public bool IsBreakingStealth()
{
return !HasAttribute(SpellAttr1.AllowWhileStealthed);
}
public bool IsRangedWeaponSpell() public bool IsRangedWeaponSpell()
{ {
return (SpellFamilyName == SpellFamilyNames.Hunter && !SpellFamilyFlags[1].HasAnyFlag(0x10000000u)) // for 53352, cannot find better way return (SpellFamilyName == SpellFamilyNames.Hunter && !SpellFamilyFlags[1].HasAnyFlag(0x10000000u)) // for 53352, cannot find better way
@@ -580,12 +575,12 @@ namespace Game.Spells
public bool IsAutoRepeatRangedSpell() public bool IsAutoRepeatRangedSpell()
{ {
return HasAttribute(SpellAttr2.AutorepeatFlag); return HasAttribute(SpellAttr2.AutoRepeat);
} }
public bool HasInitialAggro() public bool HasInitialAggro()
{ {
return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr3.NoInitialAggro)); return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr2.NoInitialThreat));
} }
public bool HasHitDelay() public bool HasHitDelay()
@@ -689,7 +684,7 @@ namespace Game.Spells
return true; return true;
// these spells (Cyclone for example) can pierce all... // these spells (Cyclone for example) can pierce all...
if (HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || HasAttribute(SpellAttr2.NoSchoolImmunities))
{ {
// ...but not these (Divine shield, Ice block, Cyclone and Banish for example) // ...but not these (Divine shield, Ice block, Cyclone and Banish for example)
if (auraSpellInfo.Mechanic != Mechanics.ImmuneShield && if (auraSpellInfo.Mechanic != Mechanics.ImmuneShield &&
@@ -717,7 +712,7 @@ namespace Game.Spells
// These auras (Cyclone for example) are not dispelable // These auras (Cyclone for example) are not dispelable
if ((auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && auraSpellInfo.Mechanic != Mechanics.None) if ((auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && auraSpellInfo.Mechanic != Mechanics.None)
|| auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) || auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
return false; return false;
return true; return true;
@@ -835,7 +830,7 @@ namespace Game.Spells
else else
{ {
// needs shapeshift // needs shapeshift
if (!HasAttribute(SpellAttr2.NotNeedShapeshift) && Stances != 0) if (!HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm) && Stances != 0)
return SpellCastResult.OnlyShapeshift; return SpellCastResult.OnlyShapeshift;
} }
@@ -1043,7 +1038,7 @@ namespace Game.Spells
if (caster.IsTypeId(TypeId.Player)) if (caster.IsTypeId(TypeId.Player))
{ {
// Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells) // Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells)
if (HasAttribute(SpellAttr2.CantTargetTapped)) if (HasAttribute(SpellAttr2.CannotCastOnTapped))
{ {
Creature targetCreature = unitTarget.ToCreature(); Creature targetCreature = unitTarget.ToCreature();
if (targetCreature != null) if (targetCreature != null)
@@ -2509,7 +2504,7 @@ namespace Game.Spells
ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo(); ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo();
if (!auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (!auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && !auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
{ {
uint schoolImmunity = immuneInfo.SchoolImmuneMask; uint schoolImmunity = immuneInfo.SchoolImmuneMask;
if (schoolImmunity != 0) if (schoolImmunity != 0)
@@ -2558,7 +2553,7 @@ namespace Game.Spells
if (!immuneInfo.AuraTypeImmune.Contains(auraName)) if (!immuneInfo.AuraTypeImmune.Contains(auraName))
isImmuneToAuraEffectApply = true; isImmuneToAuraEffectApply = true;
if (!isImmuneToAuraEffectApply && !auraSpellInfo.IsPositiveEffect(auraSpellEffectInfo.EffectIndex) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) if (!isImmuneToAuraEffectApply && !auraSpellInfo.IsPositiveEffect(auraSpellEffectInfo.EffectIndex) && !auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities))
{ {
uint applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask; uint applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask;
if (applyHarmfulAuraImmunityMask != 0) if (applyHarmfulAuraImmunityMask != 0)
@@ -2604,7 +2599,7 @@ namespace Game.Spells
break; break;
case AuraType.SchoolImmunity: case AuraType.SchoolImmunity:
case AuraType.ModImmuneAuraApplySchool: case AuraType.ModImmuneAuraApplySchool:
if (aurEff.GetSpellInfo().HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune) || !Convert.ToBoolean((uint)aurEff.GetSpellInfo().SchoolMask & miscValue)) if (aurEff.GetSpellInfo().HasAttribute(SpellAttr2.NoSchoolImmunities) || !Convert.ToBoolean((uint)aurEff.GetSpellInfo().SchoolMask & miscValue))
continue; continue;
break; break;
case AuraType.DispelImmunity: case AuraType.DispelImmunity:
@@ -3180,7 +3175,7 @@ namespace Game.Spells
return this; return this;
// Client ignores spell with these attributes (sub_53D9D0) // Client ignores spell with these attributes (sub_53D9D0)
if (HasAttribute(SpellAttr0.AuraIsDebuff) || HasAttribute(SpellAttr2.Unk3) || HasAttribute(SpellAttr3.DrainSoul)) if (HasAttribute(SpellAttr0.AuraIsDebuff) || HasAttribute(SpellAttr2.AllowLowLevelBuff) || HasAttribute(SpellAttr3.DrainSoul))
return this; return this;
bool needRankSelection = false; bool needRankSelection = false;
+3 -3
View File
@@ -4098,7 +4098,7 @@ namespace Game.Entities
ApplySpellFix(new[] { 75509 }, spellInfo => ApplySpellFix(new[] { 75509 }, spellInfo =>
{ {
spellInfo.AttributesEx6 |= SpellAttr6.CanTargetInvisible; spellInfo.AttributesEx6 |= SpellAttr6.CanTargetInvisible;
spellInfo.AttributesEx2 |= SpellAttr2.CanTargetNotInLos; spellInfo.AttributesEx2 |= SpellAttr2.IgnoreLineOfSight;
}); });
// Awaken Flames // Awaken Flames
@@ -4122,7 +4122,7 @@ namespace Game.Entities
{ {
// All spells work even without these changes. The LOS attribute is due to problem // All spells work even without these changes. The LOS attribute is due to problem
// from collision between maps & gos with active destroyed state. // from collision between maps & gos with active destroyed state.
spellInfo.AttributesEx2 |= SpellAttr2.CanTargetNotInLos; spellInfo.AttributesEx2 |= SpellAttr2.IgnoreLineOfSight;
}); });
// Arcane Barrage (cast by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)). // Arcane Barrage (cast by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)).
@@ -4261,7 +4261,7 @@ namespace Game.Entities
ApplySpellFix(new[] { 42525 }, spellInfo => ApplySpellFix(new[] { 42525 }, spellInfo =>
{ {
spellInfo.AttributesEx3 |= SpellAttr3.DeathPersistent; spellInfo.AttributesEx3 |= SpellAttr3.DeathPersistent;
spellInfo.AttributesEx2 |= SpellAttr2.CanTargetDead; spellInfo.AttributesEx2 |= SpellAttr2.AllowDeadTarget;
}); });
// Soul Sickness (Forge of Souls) // Soul Sickness (Forge of Souls)
+3 -5
View File
@@ -1175,11 +1175,9 @@ namespace Scripts.Spells.Shaman
caster.m_Events.AddEventAtOffset(() => caster.m_Events.AddEventAtOffset(() =>
{ {
var targets = new CastSpellTargetArg(procInfo.GetProcTarget()); CastSpellExtraArgs args = new();
var overloadSpellId = GetTriggeredSpellId(procInfo.GetSpellInfo().Id); args.OriginalCastId = procInfo.GetProcSpell().m_castId;
var args = new CastSpellExtraArgs(procInfo.GetProcSpell()); caster.CastSpell(new CastSpellTargetArg(procInfo.GetProcTarget()), GetTriggeredSpellId(procInfo.GetSpellInfo().Id), args);
caster.CastSpell(targets, overloadSpellId, args);
}, TimeSpan.FromMilliseconds(400)); }, TimeSpan.FromMilliseconds(400));
} }