From a198e03a1d7dea113a18a8d07359265198b5a2ba Mon Sep 17 00:00:00 2001 From: hondacrx Date: Wed, 1 Jun 2022 11:53:42 -0400 Subject: [PATCH] Core/Spells: Rename SpellAttr2 to use official attribute names Port From (https://github.com/TrinityCore/TrinityCore/commit/dda375b9868d6dbe2a4d58b386bb90ae41d25e0d) --- .../Framework/Constants/Spells/SpellConst.cs | 64 +++++------ Source/Game/Entities/Object/WorldObject.cs | 16 ++- Source/Game/Entities/Player/Player.Items.cs | 2 +- Source/Game/Entities/Player/Player.Spells.cs | 4 +- Source/Game/Entities/Unit/Unit.Spells.cs | 103 ++++++++++++------ Source/Game/Entities/Unit/Unit.cs | 6 +- Source/Game/Spells/Auras/Aura.cs | 61 ++++++----- Source/Game/Spells/Auras/AuraEffect.cs | 8 +- Source/Game/Spells/Spell.cs | 82 +++++++++++--- Source/Game/Spells/SpellEffects.cs | 26 +++-- Source/Game/Spells/SpellInfo.cs | 27 ++--- Source/Game/Spells/SpellManager.cs | 6 +- Source/Scripts/Spells/Shaman.cs | 8 +- 13 files changed, 256 insertions(+), 157 deletions(-) diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index ad54216b9..707462473 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -1653,38 +1653,38 @@ namespace Framework.Constants } public enum SpellAttr2 : uint { - CanTargetDead = 0x01, // 0 Can Target Dead Unit Or Corpse - Unk1 = 0x02, // 1 Vanish, Shadowform, Ghost Wolf And Other - CanTargetNotInLos = 0x04, // 2 26368 4.0.1 Dbc Change - Unk3 = 0x08, // 3 - DisplayInStanceBar = 0x10, // 4 Client Displays Icon In Stance Bar When Learned, Even If Not Shapeshift - AutorepeatFlag = 0x20, // 5 - CantTargetTapped = 0x40, // 6 Target Must Be Tapped By Caster - Unk7 = 0x80, // 7 - Unk8 = 0x100, // 8 Not Set In 3.0.3 - Unk9 = 0x200, // 9 - Unk10 = 0x400, // 10 Related To Tame - HealthFunnel = 0x800, // 11 - Unk12 = 0x1000, // 12 Cleave, Heart Strike, Maul, Sunder Armor, Swipe - PreserveEnchantInArena = 0x2000, // 13 Items Enchanted By Spells With This Flag Preserve The Enchant To Arenas - Unk14 = 0x4000, // 14 - Unk15 = 0x8000, // 15 Not Set In 3.0.3 - TameBeast = 0x10000, // 16 - NotResetAutoActions = 0x20000, // 17 Don'T Reset Timers For Melee Autoattacks (Swings) Or Ranged Autoattacks (Autoshoots) - ReqDeadPet = 0x40000, // 18 Only Revive Pet And Heart Of The Pheonix - NotNeedShapeshift = 0x80000, // 19 Does Not Necessarly Need Shapeshift - Unk20 = 0x100000, // 20 - DamageReducedShield = 0x200000, // 21 For Ice Blocks, Pala Immunity Buffs, Priest Absorb Shields, But Used Also For Other Spells . Not Sure! - Unk22 = 0x400000, // 22 Ambush, Backstab, Cheap Shot, Death Grip, Garrote, Judgements, Mutilate, Pounce, Ravage, Shiv, Shred - IsArcaneConcentration = 0x800000, // 23 Only Mage Arcane Concentration Have This Flag - Unk24 = 0x1000000, // 24 - Unk25 = 0x2000000, // 25 - UnaffectedByAuraSchoolImmune = 0x4000000, // 26 Unaffected By School Immunity - Unk27 = 0x8000000, // 27 - IgnoreActionAuraInterruptFlags = 0x10000000, // 28 doesnt break auras with SpellAuraInterruptFlags::Action and SpellAuraInterruptFlags::ActionDelayed - CantCrit = 0x20000000, // 29 Spell Can'T Crit - ActiveThreat = 0x40000000, // 30 Active Threat - FoodBuff = 0x80000000 // 31 Food Or Drink Buff (Like Well Fed) + AllowDeadTarget = 0x01, // Allow Dead Target + NoShapeshiftUi = 0x02, // No Shapeshift Ui (Client Only) Description Does Not Replace Action Bar When Shapeshifted + IgnoreLineOfSight = 0x04, // Ignore Line Of Sight + AllowLowLevelBuff = 0x08, // Allow Low Level Buff + UseShapeshiftBar = 0x10, // Use Shapeshift Bar (Client Only) + AutoRepeat = 0x20, // Auto Repeat + CannotCastOnTapped = 0x40, // Cannot Cast On Tapped Description Can Only Target Untapped Units, Or Those Tapped By Caster + DoNotReportSpellFailure = 0x80, // Do Not Report Spell Failure + IncludeInAdvancedCombatLog = 0x100, // Include In Advanced Combat Log (Client Only) Description Determines Whether To Include This Aura In List Of Auras In SmsgEncounterStart + AlwaysCastAsUnit = 0x200, /*Nyi, Unk*/ // Always Cast As Unit + SpecialTamingFlag = 0x400, // Special Taming Flag Description Related To Taming? + NoTargetPerSecondCosts = 0x800, // No Target Per-Second Costs + ChainFromCaster = 0x1000, // Chain From Caster + EnchantOwnItemOnly = 0x2000, // Enchant Own Item Only + AllowWhileInvisible = 0x4000, // Allow While Invisible + DoNotConsumeIfGainedDuringCast = 0x8000, // Do Not Consume If Gained During Cast + NoActivePets = 0x10000, // No Active Pets + DoNotResetCombatTimers = 0x20000, // Do Not Reset Combat Timers Description Does Not Reset Melee/Ranged Autoattack Timer On Cast + NoJumpWhileCastPending = 0x40000, // No Jump While Cast Pending (Client Only) + 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) + InitiateCombatPostCastEnablesAutoAttack = 0x100000, // Initiate Combat Post-Cast (Enables Auto-Attack) + FailOnAllTargetsImmune = 0x200000, // Fail On All Targets Immune Description Causes Bg Flags To Be Dropped If Combined With Attr1DispelAurasOnImmunity + NoInitialThreat = 0x400000, // No Initial Threat + ProcCooldownOnFailure = 0x800000, // Proc Cooldown On Failure + ItemCastWithOwnerSkill = 0x1000000, // Item Cast With Owner Skill + DontBlockManaRegen = 0x2000000, // Don'T Block Mana Regen + NoSchoolImmunities = 0x4000000, // No School Immunities Description Allow Aura To Be Applied Despite Target Being Immune To New Aura Applications + IgnoreWeaponskill = 0x8000000, // Ignore Weaponskill + NotAnAction = 0x10000000, // Not An Action + CantCrit = 0x20000000, // Can'T Crit + ActiveThreat = 0x40000000, // Active Threat + RetainItemCast = 0x80000000 // Retain Item Cast Description Passes MCastitem To Triggered Spells } public enum SpellAttr3 : uint { diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 4a516d225..070ac58b4 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1917,7 +1917,7 @@ namespace Game.Entities if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) && ((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature())) 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]); else if (Global.SpellMgr.IsPartOfSkillLine(SkillType.Cooking, spellInfo.Id) && unitCaster.HasAura(67556)) // cooking with Chef Hat. castTime = 500; @@ -1943,7 +1943,7 @@ namespace Game.Entities if (!(spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr0.IsTradeskill) || spellInfo.HasAttribute(SpellAttr3.NoDoneBonus)) && ((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature())) 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]); } @@ -2369,6 +2369,18 @@ namespace Game.Entities if (args.OriginalCastItemLevel.HasValue) 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); } diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index ae820d874..33bc12121 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -3921,7 +3921,7 @@ namespace Game.Entities Aura itemAura = GetAura((uint)effectData.SpellID, GetGUID(), pItem.GetGUID()); if (itemAura != null) - itemAura.AddProcCooldown(now + TimeSpan.FromMilliseconds(procEntry.Cooldown)); + itemAura.AddProcCooldown(procEntry, now); continue; } diff --git a/Source/Game/Entities/Player/Player.Spells.cs b/Source/Game/Entities/Player/Player.Spells.cs index e9c1b8a6e..3801f7a5b 100644 --- a/Source/Game/Entities/Player/Player.Spells.cs +++ b/Source/Game/Entities/Player/Player.Spells.cs @@ -1261,7 +1261,7 @@ namespace Game.Entities uint SkillValue = GetPureSkillValue((SkillType)_spell_idx.SkillupSkillLineID); // 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); if (discoveredSpell != 0) @@ -2277,7 +2277,7 @@ namespace Game.Entities // talent dependent passives activated at form apply have proper stance data ShapeShiftForm form = GetShapeshiftForm(); 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 // passive spells which apply aura and have an item requirement are to be added manually, instead of casted diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 6143dca87..f3779fcab 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1343,7 +1343,7 @@ namespace Game.Entities return true; } - if (!spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + if (!spellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities)) { // Check for immune to application of harmful magical effects var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool); @@ -1382,7 +1382,7 @@ namespace Game.Entities if (spellInfo.HasAttribute(SpellAttr0.NoImmunities) && spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) return false; - if (spellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + if (spellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || spellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities)) return false; uint schoolMask = (uint)spellInfo.GetSchoolMask(); @@ -1422,7 +1422,7 @@ namespace Game.Entities 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) { WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack; @@ -1482,32 +1482,49 @@ namespace Game.Entities { 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 if (procAuras != null) { foreach (AuraApplication aurApp in procAuras) { Cypher.Assert(aurApp.GetTarget() == this); - uint procEffectMask = aurApp.GetBase().GetProcEffectMask(aurApp, eventInfo, now); - if (procEffectMask != 0) - { - aurApp.GetBase().PrepareProcToTrigger(aurApp, eventInfo, now); - aurasTriggeringProc.Add(Tuple.Create(procEffectMask, aurApp)); - } + processAuraApplication(aurApp); } } // or generate one on our own else { foreach (var pair in GetAppliedAuras()) - { - 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)); - } - } + processAuraApplication(pair.Value); } } @@ -1556,11 +1573,8 @@ namespace Game.Entities if (disableProcs) 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) continue; @@ -1694,7 +1708,7 @@ namespace Game.Entities { if (!skipInstant || currentSpell.GetCastTime() != 0) { - if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) + if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers)) return true; } } @@ -1703,7 +1717,7 @@ namespace Game.Entities if (!skipChanneled && currentSpell && (currentSpell.GetState() != SpellState.Finished)) { - if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) + if (!isAutoshoot || !currentSpell.m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers)) return true; } currentSpell = GetCurrentSpell(CurrentSpellTypes.AutoRepeat); @@ -2494,7 +2508,7 @@ namespace Game.Entities if (spellInfo == null) return null; - if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.CanTargetDead)) + if (!target.IsAlive() && !spellInfo.IsPassive() && !spellInfo.HasAttribute(SpellAttr2.AllowDeadTarget)) return null; if (target.IsImmunedToSpell(spellInfo, this)) @@ -2823,16 +2837,35 @@ namespace Game.Entities 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; } - public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint except = 0) + public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, SpellInfo source = null) { if (!HasInterruptFlag(flag)) return; @@ -2842,7 +2875,7 @@ namespace Game.Entities { 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; RemoveAura(aura, AuraRemoveMode.Interrupt); @@ -2857,15 +2890,15 @@ namespace Game.Entities { if (spell.GetState() == SpellState.Casting && spell.GetSpellInfo().HasChannelInterruptFlag(flag) - && spell.GetSpellInfo().Id != except - && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo())) + && (source == null || spell.GetSpellInfo().Id != source.Id) + && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo(), source)) InterruptNonMeleeSpells(false); } UpdateInterruptMask(); } - public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, uint except = 0) + public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, SpellInfo source = null) { if (!HasInterruptFlag(flag)) return; @@ -2875,7 +2908,7 @@ namespace Game.Entities { 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; RemoveAura(aura, AuraRemoveMode.Interrupt); @@ -2890,8 +2923,8 @@ namespace Game.Entities { if (spell.GetState() == SpellState.Casting && spell.GetSpellInfo().HasChannelInterruptFlag(flag) - && spell.GetSpellInfo().Id != except - && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo())) + && (source == null || spell.GetSpellInfo().Id != source.Id) + && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo(), source)) InterruptNonMeleeSpells(false); } diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index b11952707..c0983a0ca 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -2441,10 +2441,10 @@ namespace Game.Entities if (spellProto != null) { if (!spellProto.HasAttribute(SpellAttr4.DamageDoesntBreakAuras)) - victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto.Id); + victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto); } else - victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, 0); + victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage); if (damage == 0 && damagetype != DamageEffectType.DOT && cleanDamage != null && cleanDamage.absorbed_damage != 0) { @@ -2649,7 +2649,7 @@ namespace Game.Entities victim.ModifyHealth(-(int)damage); 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)) { diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index bb563d6be..30cb30271 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -698,7 +698,7 @@ namespace Game.Spells { if (m_timeCla > diff) m_timeCla -= (int)diff; - else if (caster != null) + else if (caster != null && (caster == GetOwner() || !GetSpellInfo().HasAttribute(SpellAttr2.NoTargetPerSecondCosts))) { if (!m_periodicCosts.Empty()) { @@ -1008,7 +1008,7 @@ namespace Game.Spells { return GetCasterGUID() == target.GetGUID() && m_spellInfo.Stances != 0 - && !m_spellInfo.HasAttribute(SpellAttr2.NotNeedShapeshift) + && !m_spellInfo.HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm) && !m_spellInfo.HasAttribute(SpellAttr0.NotShapeshifted); } @@ -1644,9 +1644,19 @@ namespace Game.Spells 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() @@ -1663,26 +1673,36 @@ namespace Game.Spells SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetSpellInfo()); 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) if (!procEntry.AttributesMask.HasAnyFlag(ProcAttributes.UseStacksForCharges) && IsUsingCharges() && (eventInfo.GetSpellInfo() == null || !eventInfo.GetSpellInfo().HasAttribute(SpellAttr6.DoNotConsumeResources))) { --m_procCharges; SetNeedClientUpdateForTargets(); } + } - // cooldowns should be added to the whole aura (see 51698 area aura) - int procCooldown = (int)procEntry.Cooldown; - Unit caster = GetCaster(); - if (caster != null) + public void ConsumeProcCharges(SpellProcEntry procEntry) + { + // Remove aura if we've used last charge to proc + if (procEntry.AttributesMask.HasFlag(ProcAttributes.UseStacksForCharges)) { - Player modOwner = caster.GetSpellModOwner(); - if (modOwner != null) - modOwner.ApplySpellMod(GetSpellInfo(), SpellModOp.ProcCooldown, ref procCooldown); + ModStackAmount(-1); + } + else if (IsUsingCharges()) + { + if (GetCharges() == 0) + Remove(); } - - AddProcCooldown(now + TimeSpan.FromMilliseconds(procCooldown)); - - SetLastProcSuccessTime(now); } public uint GetProcEffectMask(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now) @@ -1859,16 +1879,7 @@ namespace Game.Spells CallScriptAfterProcHandlers(aurApp, eventInfo); } - // Remove aura if we've used last charge to proc - if (Global.SpellMgr.GetSpellProcEntry(m_spellInfo).AttributesMask.HasAnyFlag(ProcAttributes.UseStacksForCharges)) - { - ModStackAmount(-1); - } - else if (IsUsingCharges()) - { - if (GetCharges() == 0) - Remove(); - } + ConsumeProcCharges(Global.SpellMgr.GetSpellProcEntry(GetSpellInfo())); } public float CalcPPMProcChance(Unit actor) diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index fba2c7d7e..092acaa25 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -1308,7 +1308,7 @@ namespace Game.Spells } if (!shapeInfo.Flags.HasAnyFlag(SpellShapeshiftFormFlags.Stance)) - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Shapeshifting, GetId()); + target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Shapeshifting, GetSpellInfo()); } else { @@ -2837,7 +2837,7 @@ namespace Game.Spells // remove all flag auras (they are positive, but they must be removed when you are immune) if (GetSpellInfo().HasAttribute(SpellAttr1.ImmunityPurgesEffect) - && GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield)) + && GetSpellInfo().HasAttribute(SpellAttr2.FailOnAllTargetsImmune)) target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); } @@ -5206,10 +5206,6 @@ namespace Game.Spells 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 if (GetBase().IsPermanent() && target.IsFullHealth()) return; diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index e5c11023e..8a2b923e2 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -95,6 +95,10 @@ namespace Game.Spells m_spellState = SpellState.None; _triggeredCastFlags = triggerFlags; + + if (info.HasAttribute(SpellAttr2.DoNotReportSpellFailure)) + _triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.DontReportCastError; + if (m_spellInfo.HasAttribute(SpellAttr4.CanCastWhileCasting)) _triggeredCastFlags = _triggeredCastFlags | TriggerCastFlags.IgnoreCastInProgress; @@ -274,6 +278,35 @@ namespace Game.Spells if (m_targets.HasDst()) 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()) { // maybe do this for all spells? @@ -1621,8 +1654,9 @@ namespace Game.Spells if (isBouncingFar) searchRadius *= chainTargets; + WorldObject chainSource = m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster) ? m_caster : target; List tempTargets = new(); - SearchAreaTargets(tempTargets, searchRadius, target.GetPosition(), m_caster, objectType, selectType, condList); + SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, condList); tempTargets.Remove(target); // remove targets which are always invalid for chain spells @@ -1651,7 +1685,7 @@ namespace Game.Spells if (unitTarget != null) { 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; maxHPDeficit = deficit; @@ -1666,19 +1700,22 @@ namespace Game.Spells { 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; } - 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; } } // not found any valid target - chain ends if (found == null) break; - target = found; + + if (!m_spellInfo.HasAttribute(SpellAttr2.ChainFromCaster)) + chainSource = found; + + targets.Add(found); tempTargets.Remove(found); - targets.Add(target); --chainTargets; } } @@ -1712,7 +1749,7 @@ namespace Game.Spells break; case SpellDmgClass.Ranged: // Auto attack - if (m_spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) + if (m_spellInfo.HasAttribute(SpellAttr2.AutoRepeat)) { m_procAttacker = new ProcFlagsInit(ProcFlags.DealRangedAttack); m_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack); @@ -1726,7 +1763,7 @@ namespace Game.Spells default: if (m_spellInfo.EquippedItemClass == ItemClass.Weapon && 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_procVictim = new ProcFlagsInit(ProcFlags.TakeRangedAttack); @@ -2488,8 +2525,8 @@ namespace Game.Spells { // 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) - if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && m_spellInfo.IsBreakingStealth() && !m_spellInfo.HasAttribute(SpellAttr2.IgnoreActionAuraInterruptFlags)) - unitCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Action); + if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.NotAnAction)) + unitCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Action, m_spellInfo); // 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 @@ -2903,8 +2940,8 @@ namespace Game.Spells if (!hitMask.HasAnyFlag(ProcFlagsHit.Critical)) hitMask |= ProcFlagsHit.Normal; - if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.IgnoreActionAuraInterruptFlags)) - m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed); + if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.NotAnAction)) + 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); @@ -3340,7 +3377,7 @@ namespace Game.Spells if (IsAutoActionResetSpell()) { - if (!m_spellInfo.HasAttribute(SpellAttr2.NotResetAutoActions)) + if (!m_spellInfo.HasAttribute(SpellAttr2.DoNotResetCombatTimers)) { unitCaster.ResetAttackTimer(WeaponAttackType.BaseAttack); if (unitCaster.HaveOffhandWeapon()) @@ -4566,7 +4603,7 @@ namespace Game.Spells if (m_spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) || m_spellInfo.IsNextMeleeSwingSpell() || m_spellInfo.HasAttribute(SpellAttr1.InitiatesCombatEnablesAutoAttack) - || m_spellInfo.HasAttribute(SpellAttr2.Unk20) + || m_spellInfo.HasAttribute(SpellAttr2.InitiateCombatPostCastEnablesAutoAttack) || m_spellInfo.HasEffect(SpellEffectName.Attack) || m_spellInfo.HasEffect(SpellEffectName.NormalizedWeaponDmg) || m_spellInfo.HasEffect(SpellEffectName.WeaponDamageNoSchool) @@ -4787,7 +4824,7 @@ namespace Game.Spells 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)) return SpellCastResult.LineOfSight; } @@ -4800,7 +4837,7 @@ namespace Game.Spells float x, y, 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)) return SpellCastResult.LineOfSight; } @@ -4808,6 +4845,10 @@ namespace Game.Spells // check pet presence if (unitCaster != null) { + if (m_spellInfo.HasAttribute(SpellAttr2.NoActivePets)) + if (!unitCaster.GetPetGUID().IsEmpty()) + return SpellCastResult.AlreadyHavePet; + foreach (var spellEffectInfo in m_spellInfo.GetEffects()) { if (spellEffectInfo.TargetA.GetTarget() == Targets.UnitPet) @@ -5697,6 +5738,9 @@ namespace Game.Spells if (m_CastItem != null) return SpellCastResult.ItemEnchantTradeWindow; + if (m_spellInfo.HasAttribute(SpellAttr2.EnchantOwnItemOnly)) + return SpellCastResult.ItemEnchantTradeWindow; + if (!m_caster.IsTypeId(TypeId.Player)) return SpellCastResult.NotTrading; @@ -6964,7 +7008,7 @@ namespace Game.Spells } // 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; // check if gameobject ignores LOS @@ -6974,7 +7018,7 @@ namespace Game.Spells return true; // 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; // @todo shit below shouldn't be here, but it's temporary @@ -9052,6 +9096,7 @@ namespace Game.Spells { public TriggerCastFlags TriggerFlags; public Item CastItem; + public Spell TriggeringSpell; public AuraEffect TriggeringAura; public ObjectGuid OriginalCaster = ObjectGuid.Empty; public Difficulty CastDifficulty; @@ -9113,6 +9158,7 @@ namespace Game.Spells public CastSpellExtraArgs SetTriggeringSpell(Spell triggeringSpell) { + TriggeringSpell = triggeringSpell; if (triggeringSpell != null) { OriginalCastItemLevel = triggeringSpell.m_castItemLevel; diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 56b73fd62..ffecea77a 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -305,18 +305,26 @@ namespace Game.Spells if (effectInfo.Effect == SpellEffectName.TriggerSpell) 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(() => { // 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); } diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 434814c26..7efe3a928 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -499,7 +499,7 @@ namespace Game.Spells 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; foreach (var effectInfo in _effects) @@ -566,11 +566,6 @@ namespace Game.Spells return HasAttribute(SpellAttr0.OnNextSwingNoDamage | SpellAttr0.OnNextSwing); } - public bool IsBreakingStealth() - { - return !HasAttribute(SpellAttr1.AllowWhileStealthed); - } - public bool IsRangedWeaponSpell() { return (SpellFamilyName == SpellFamilyNames.Hunter && !SpellFamilyFlags[1].HasAnyFlag(0x10000000u)) // for 53352, cannot find better way @@ -580,12 +575,12 @@ namespace Game.Spells public bool IsAutoRepeatRangedSpell() { - return HasAttribute(SpellAttr2.AutorepeatFlag); + return HasAttribute(SpellAttr2.AutoRepeat); } public bool HasInitialAggro() { - return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr3.NoInitialAggro)); + return !(HasAttribute(SpellAttr1.NoThreat) || HasAttribute(SpellAttr2.NoInitialThreat)); } public bool HasHitDelay() @@ -689,7 +684,7 @@ namespace Game.Spells return true; // 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) if (auraSpellInfo.Mechanic != Mechanics.ImmuneShield && @@ -717,7 +712,7 @@ namespace Game.Spells // These auras (Cyclone for example) are not dispelable if ((auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && auraSpellInfo.Mechanic != Mechanics.None) - || auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + || auraSpellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities)) return false; return true; @@ -835,7 +830,7 @@ namespace Game.Spells else { // needs shapeshift - if (!HasAttribute(SpellAttr2.NotNeedShapeshift) && Stances != 0) + if (!HasAttribute(SpellAttr2.AllowWhileNotShapeshiftedCasterForm) && Stances != 0) return SpellCastResult.OnlyShapeshift; } @@ -1043,7 +1038,7 @@ namespace Game.Spells if (caster.IsTypeId(TypeId.Player)) { // Do not allow these spells to target creatures not tapped by us (Banish, Polymorph, many quest spells) - if (HasAttribute(SpellAttr2.CantTargetTapped)) + if (HasAttribute(SpellAttr2.CannotCastOnTapped)) { Creature targetCreature = unitTarget.ToCreature(); if (targetCreature != null) @@ -2509,7 +2504,7 @@ namespace Game.Spells 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; if (schoolImmunity != 0) @@ -2558,7 +2553,7 @@ namespace Game.Spells if (!immuneInfo.AuraTypeImmune.Contains(auraName)) 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; if (applyHarmfulAuraImmunityMask != 0) @@ -2604,7 +2599,7 @@ namespace Game.Spells break; case AuraType.SchoolImmunity: 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; break; case AuraType.DispelImmunity: @@ -3180,7 +3175,7 @@ namespace Game.Spells return this; // 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; bool needRankSelection = false; diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index 928288aaf..efa728697 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -4098,7 +4098,7 @@ namespace Game.Entities ApplySpellFix(new[] { 75509 }, spellInfo => { spellInfo.AttributesEx6 |= SpellAttr6.CanTargetInvisible; - spellInfo.AttributesEx2 |= SpellAttr2.CanTargetNotInLos; + spellInfo.AttributesEx2 |= SpellAttr2.IgnoreLineOfSight; }); // Awaken Flames @@ -4122,7 +4122,7 @@ namespace Game.Entities { // All spells work even without these changes. The LOS attribute is due to problem // 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)). @@ -4261,7 +4261,7 @@ namespace Game.Entities ApplySpellFix(new[] { 42525 }, spellInfo => { spellInfo.AttributesEx3 |= SpellAttr3.DeathPersistent; - spellInfo.AttributesEx2 |= SpellAttr2.CanTargetDead; + spellInfo.AttributesEx2 |= SpellAttr2.AllowDeadTarget; }); // Soul Sickness (Forge of Souls) diff --git a/Source/Scripts/Spells/Shaman.cs b/Source/Scripts/Spells/Shaman.cs index 446a2122b..66b7817c9 100644 --- a/Source/Scripts/Spells/Shaman.cs +++ b/Source/Scripts/Spells/Shaman.cs @@ -1175,11 +1175,9 @@ namespace Scripts.Spells.Shaman caster.m_Events.AddEventAtOffset(() => { - var targets = new CastSpellTargetArg(procInfo.GetProcTarget()); - var overloadSpellId = GetTriggeredSpellId(procInfo.GetSpellInfo().Id); - var args = new CastSpellExtraArgs(procInfo.GetProcSpell()); - - caster.CastSpell(targets, overloadSpellId, args); + CastSpellExtraArgs args = new(); + args.OriginalCastId = procInfo.GetProcSpell().m_castId; + caster.CastSpell(new CastSpellTargetArg(procInfo.GetProcTarget()), GetTriggeredSpellId(procInfo.GetSpellInfo().Id), args); }, TimeSpan.FromMilliseconds(400)); }