From 8cddeb0fc5f1dcf1215f2fae049786e85dfdede2 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Wed, 1 Jun 2022 13:01:55 -0400 Subject: [PATCH] Core/Spells: Rename SpellAttr3 to use official attribute names Port From (https://github.com/TrinityCore/TrinityCore/commit/88d7b58a3dd8b0eb95c233a20c1608ddce73d9ea) --- .../Framework/Constants/Spells/SpellConst.cs | 64 +++++++++---------- Source/Game/AI/CoreAI/UnitAI.cs | 4 +- Source/Game/Combat/ThreatManager.cs | 2 +- Source/Game/Entities/Object/WorldObject.cs | 11 ++-- Source/Game/Entities/Unit/Unit.Spells.cs | 30 ++++----- Source/Game/Maps/GridNotifiers.cs | 2 +- Source/Game/Spells/Auras/Aura.cs | 10 ++- Source/Game/Spells/Spell.cs | 53 ++++++++------- Source/Game/Spells/SpellInfo.cs | 22 +++---- Source/Game/Spells/SpellManager.cs | 46 ++++--------- 10 files changed, 118 insertions(+), 126 deletions(-) diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index 707462473..ebdf86cf5 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -1688,38 +1688,38 @@ namespace Framework.Constants } public enum SpellAttr3 : uint { - Unk0 = 0x01, // 0 - NoProcEquipRequirement = 0x02, // 1 Ignores subclass mask check when checking proc - Unk2 = 0x04, // 2 - BlockableSpell = 0x08, // 3 Only Dmg Class Melee In 3.1.3 - IgnoreResurrectionTimer = 0x10, // 4 You Don'T Have To Wait To Be Resurrected With These Spells - NoDurabilityLoss = 0x20, // 5 No Durability Loss - Unk6 = 0x40, // 6 - StackForDiffCasters = 0x80, // 7 Separate Stack For Every Caster - OnlyTargetPlayers = 0x100, // 8 Can Only Target Players - NotAProc = 0x200, // 9 Without this attribute, any triggered spell will be unable to trigger other auras' procs - MainHand = 0x400, // 10 Main Hand Weapon Required - Battleground = 0x800, // 11 Can Casted Only On Battleground - OnlyTargetGhosts = 0x1000, // 12 - DontDisplayChannelBar = 0x2000, // 13 Clientside attribute - will not display channeling bar - IsHonorlessTarget = 0x4000, // 14 "Honorless Target" Only This Spells Have This Flag - Unk15 = 0x8000, // 15 Auto Shoot, Shoot, Throw, - This Is Autoshot Flag - CantTriggerProc = 0x10000, // 16 Confirmed With Many Patchnotes - NoInitialAggro = 0x20000, // 17 Soothe Animal, 39758, Mind Soothe - IgnoreHitResult = 0x40000, // 18 Spell Should Always Hit Its Target - DisableProc = 0x80000, // 19 During Aura Proc No Spells Can Trigger (20178, 20375) - DeathPersistent = 0x100000, // 20 Death Persistent Spells - Unk21 = 0x200000, // 21 Unused - ReqWand = 0x400000, // 22 Req Wand - Unk23 = 0x800000, // 23 - ReqOffhand = 0x1000000, // 24 Req Offhand Weapon - TreatAsPeriodic = 0x2000000, // 25 Makes the spell appear as periodic in client combat logs - used by spells that trigger another spell on each tick - CanProcFromProcs = 0x4000000, // 26 Can Proc From Procs - DrainSoul = 0x8000000, // 27 Only Drain Soul Has This Flag - Unk28 = 0x10000000, // 28 - NoDoneBonus = 0x20000000, // 29 Ignore Caster Spellpower And Done Damage Mods? Client Doesn'T Apply Spellmods For Those Spells - DontDisplayRange = 0x40000000, // 30 Client Doesn'T Display Range In Tooltip For Those Spells - Unk31 = 0x80000000 // 31 + PvpEnabling = 0x01, // Pvp Enabling + NoProcEquipRequirement = 0x02, // No Proc Equip Requirement Description Ignores Subclass Mask Check When Checking Proc + NoCastingBarText = 0x04, // No Casting Bar Text + CompletelyBlocked = 0x08, // Completely Blocked + NoResTimer = 0x10, // No Res Timer + NoDurabilityLoss = 0x20, // No Durability Loss + NoAvoidance = 0x40, // No Avoidance + DotStackingRule = 0x80, // Dot Stacking Rule Description Stack Separately For Each Caster + OnlyOnPlayer = 0x100, // Only On Player + NotAProc = 0x200, // Not A Proc Description Without This Attribute, Any Triggered Spell Will Be Unable To Trigger Other Auras' Procs + RequiresMainHandWeapon = 0x400, // Requires Main-Hand Weapon + OnlyBattlegrounds = 0x800, // Only Battlegrounds + OnlyOnGhosts = 0x1000, // Only On Ghosts + HideChannelBar = 0x2000, // Hide Channel Bar (Client Only) + HideInRaidFilter = 0x4000, // Hide In Raid Filter (Client Only) + NormalRangedAttack = 0x8000, // Normal Ranged Attack Description Auto Shoot, Shoot, Throw - Ranged Normal Attack Attribute? + SuppressCasterProcs = 0x10000, // Suppress Caster Procs + SuppressTargetProcs = 0x20000, // Suppress Target Procs + AlwaysHit = 0x40000, // Always Hit Description Spell Cannot Miss, Or Be Dodged/Parried/Blocked + InstantTargetProcs = 0x80000, // Instant Target Procs Description Proc Events Are Triggered Before Spell Batching Processes The Spell Hit On Target + AllowAuraWhileDead = 0x100000, // Allow Aura While Dead + OnlyProcOutdoors = 0x200000, // Only Proc Outdoors + DoNotTriggerTargetStand = 0x400000, // Do Not Trigger Target Stand + NoDamageHistory = 0x800000, /*Nyi, No Damage History Implementation*/ // No Damage History + RequiresOffHandWeapon = 0x1000000, // Requires Off-Hand Weapon + TreatAsPeriodic = 0x2000000, // Treat As Periodic + CanProcFromProcs = 0x4000000, // Can Proc From Procs + OnlyProcOnCaster = 0x8000000, // Only Proc On Caster + IgnoreCasterAndTargetRestrictions = 0x10000000, /*Nyi*/ // Ignore Caster & Target Restrictions + IgnoreCasterModifiers = 0x20000000, // Ignore Caster Modifiers + DoNotDisplayRange = 0x40000000, // Do Not Display Range (Client Only) + NotOnAoeImmune = 0x80000000 /*Nyi, No Aoe Immunity Implementation*/ // Not On Aoe Immune } public enum SpellAttr4 : uint { diff --git a/Source/Game/AI/CoreAI/UnitAI.cs b/Source/Game/AI/CoreAI/UnitAI.cs index 78350cddc..2ef91c64d 100644 --- a/Source/Game/AI/CoreAI/UnitAI.cs +++ b/Source/Game/AI/CoreAI/UnitAI.cs @@ -264,7 +264,7 @@ namespace Game.AI var spellInfo = Global.SpellMgr.GetSpellInfo(spellId, me.GetMap().GetDifficultyID()); if (spellInfo != null) { - bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers); + bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer); target = SelectTarget(SelectTargetMethod.Random, 0, spellInfo.GetMaxRange(false), playerOnly); } break; @@ -278,7 +278,7 @@ namespace Game.AI var spellInfo = Global.SpellMgr.GetSpellInfo(spellId, me.GetMap().GetDifficultyID()); if (spellInfo != null) { - bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers); + bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer); float range = spellInfo.GetMaxRange(false); DefaultTargetSelector targetSelector = new(me, range, playerOnly, true, -(int)spellId); diff --git a/Source/Game/Combat/ThreatManager.cs b/Source/Game/Combat/ThreatManager.cs index 77edf7230..098684cd4 100644 --- a/Source/Game/Combat/ThreatManager.cs +++ b/Source/Game/Combat/ThreatManager.cs @@ -210,7 +210,7 @@ namespace Game.Combat { if (spell.HasAttribute(SpellAttr1.NoThreat)) return; - if (!_owner.IsEngaged() && spell.HasAttribute(SpellAttr3.NoInitialAggro)) + if (!_owner.IsEngaged() && spell.HasAttribute(SpellAttr2.NoInitialThreat)) return; } diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 070ac58b4..dc4988506 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1914,7 +1914,7 @@ namespace Game.Entities if (!unitCaster) return; - 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.IgnoreCasterModifiers)) && ((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature())) castTime = unitCaster.CanInstantCast() ? 0 : (int)(castTime * unitCaster.m_unitData.ModCastingSpeed); else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutoRepeat)) @@ -1940,7 +1940,7 @@ namespace Game.Entities if (!unitCaster) return; - 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.IgnoreCasterModifiers)) && ((IsPlayer() && spellInfo.SpellFamilyName != 0) || IsCreature())) duration = (int)(duration * unitCaster.m_unitData.ModCastingSpeed); else if (spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) && !spellInfo.HasAttribute(SpellAttr2.AutoRepeat)) @@ -1963,6 +1963,9 @@ namespace Game.Entities if (!victim.IsAlive() && !victim.IsPlayer()) return SpellMissInfo.None; + if (spellInfo.HasAttribute(SpellAttr3.NoAvoidance)) + return SpellMissInfo.None; + float missChance; if (spellInfo.HasAttribute(SpellAttr7.NoAttackMiss)) { @@ -2005,7 +2008,7 @@ namespace Game.Entities modOwner.ApplySpellMod(spellInfo, SpellModOp.HitChance, ref modHitChance); // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects - if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) + if (!spellInfo.HasAttribute(SpellAttr3.AlwaysHit)) { // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras modHitChance += victim.GetTotalAuraModifierByMiscMask(AuraType.ModAttackerSpellHitChance, (int)schoolMask); @@ -2087,7 +2090,7 @@ namespace Game.Entities return SpellMissInfo.Reflect; } - if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) + if (spellInfo.HasAttribute(SpellAttr3.AlwaysHit)) return SpellMissInfo.None; switch (spellInfo.DmgClass) diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index f3779fcab..905e87c90 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -77,7 +77,7 @@ namespace Game.Entities return pdamage; // Some spells don't benefit from done mods - if (spellProto.HasAttribute(SpellAttr3.NoDoneBonus)) + if (spellProto.HasAttribute(SpellAttr3.IgnoreCasterModifiers)) return pdamage; // For totems get damage bonus from owner @@ -117,7 +117,7 @@ namespace Game.Entities if ((spellProto.IsRangedWeaponSpell() && spellProto.DmgClass != SpellDmgClass.Melee)) attType = WeaponAttackType.RangedAttack; - if (spellProto.HasAttribute(SpellAttr3.ReqOffhand) && !spellProto.HasAttribute(SpellAttr3.MainHand)) + if (spellProto.HasAttribute(SpellAttr3.RequiresOffHandWeapon) && !spellProto.HasAttribute(SpellAttr3.RequiresMainHandWeapon)) attType = WeaponAttackType.OffAttack; float APbonus = (float)(victim.GetTotalAuraModifier(attType != WeaponAttackType.RangedAttack ? AuraType.MeleeAttackPowerAttackerBonus : AuraType.RangedAttackPowerAttackerBonus)); @@ -160,7 +160,7 @@ namespace Game.Entities return 1.0f; // Some spells don't benefit from done mods - if (spellProto.HasAttribute(SpellAttr3.NoDoneBonus)) + if (spellProto.HasAttribute(SpellAttr3.IgnoreCasterModifiers)) return 1.0f; // Some spells don't benefit from pct done mods @@ -498,7 +498,7 @@ namespace Game.Entities } // Some spells don't benefit from done mods - if (spellProto.HasAttribute(SpellAttr3.NoDoneBonus)) + if (spellProto.HasAttribute(SpellAttr3.IgnoreCasterModifiers)) return 1.0f; // Some spells don't benefit from done mods @@ -736,6 +736,9 @@ namespace Game.Entities // Melee based spells hit result calculations public override SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo) { + if (spellInfo.HasAttribute(SpellAttr3.NoAvoidance)) + return SpellMissInfo.None; + WeaponAttackType attType = WeaponAttackType.BaseAttack; // Check damage class instead of attack type to correctly handle judgements @@ -763,7 +766,7 @@ namespace Game.Entities bool canDodge = !spellInfo.HasAttribute(SpellAttr7.NoAttackDodge); bool canParry = !spellInfo.HasAttribute(SpellAttr7.NoAttackParry); - bool canBlock = spellInfo.HasAttribute(SpellAttr3.BlockableSpell); + bool canBlock = spellInfo.HasAttribute(SpellAttr3.CompletelyBlocked); // if victim is casting or cc'd it can't avoid attacks if (victim.IsNonMeleeSpellCast(false, false, true) || victim.HasUnitState(UnitState.Controlled)) @@ -1336,7 +1339,7 @@ namespace Game.Entities AuraType aura = spellEffectInfo.ApplyAuraName; if (aura != 0) { - if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) + if (!spellInfo.HasAttribute(SpellAttr3.AlwaysHit)) { var list = m_spellImmune[(int)SpellImmunity.State]; if (list.ContainsKey(aura)) @@ -1379,7 +1382,7 @@ namespace Game.Entities return false; // for example 40175 - if (spellInfo.HasAttribute(SpellAttr0.NoImmunities) && spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) + if (spellInfo.HasAttribute(SpellAttr0.NoImmunities) && spellInfo.HasAttribute(SpellAttr3.AlwaysHit)) return false; if (spellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || spellInfo.HasAttribute(SpellAttr2.NoSchoolImmunities)) @@ -1578,14 +1581,7 @@ namespace Game.Entities if (aurApp.GetRemoveMode() != 0) continue; - SpellInfo spellInfo = aurApp.GetBase().GetSpellInfo(); - if (spellInfo.HasAttribute(SpellAttr3.DisableProc)) - SetCantProc(true); - aurApp.GetBase().TriggerProcOnEvent(procEffectMask, aurApp, eventInfo); - - if (spellInfo.HasAttribute(SpellAttr3.DisableProc)) - SetCantProc(false); } if (disableProcs) @@ -1762,7 +1758,7 @@ namespace Game.Entities bool IsSpellBlocked(Unit victim, SpellInfo spellProto, WeaponAttackType attackType = WeaponAttackType.BaseAttack) { // These spells can't be blocked - if (spellProto != null && (spellProto.HasAttribute(SpellAttr0.NoActiveDefense) || spellProto.HasAttribute(SpellAttr3.IgnoreHitResult))) + if (spellProto != null && (spellProto.HasAttribute(SpellAttr0.NoActiveDefense) || spellProto.HasAttribute(SpellAttr3.AlwaysHit))) return false; // Can't block when casting/controlled @@ -1961,7 +1957,7 @@ namespace Game.Entities if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal)) { // Spells with this attribute were already calculated in MeleeSpellHitResult - if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell)) + if (!spellInfo.HasAttribute(SpellAttr3.CompletelyBlocked)) { // Get blocked status blocked = IsSpellBlocked(victim, spellInfo, attackType); @@ -3439,7 +3435,7 @@ namespace Game.Entities Aura aura = aurApp.GetBase(); return (!aura.GetSpellInfo().HasAttribute(SpellAttr4.DontRemoveInArena) // don't remove stances, shadowform, pally/hunter auras && !aura.IsPassive() // don't remove passive auras - && (aurApp.IsPositive() || !aura.GetSpellInfo().HasAttribute(SpellAttr3.DeathPersistent))) || // not negative death persistent auras + && (aurApp.IsPositive() || !aura.GetSpellInfo().HasAttribute(SpellAttr3.AllowAuraWhileDead))) || // not negative death persistent auras aura.GetSpellInfo().HasAttribute(SpellAttr5.RemoveEnteringArena); // special marker, always remove }); } diff --git a/Source/Game/Maps/GridNotifiers.cs b/Source/Game/Maps/GridNotifiers.cs index df29e9ae9..1ddfe13ee 100644 --- a/Source/Game/Maps/GridNotifiers.cs +++ b/Source/Game/Maps/GridNotifiers.cs @@ -2173,7 +2173,7 @@ namespace Game.Maps if (u.IsTypeId(TypeId.Unit) && u.IsTotem()) return false; - if (_spellInfo != null && _spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers) && !u.IsPlayer()) + if (_spellInfo != null && _spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer) && !u.IsPlayer()) return false; if (!i_funit.IsValidAttackTarget(u, _spellInfo)) diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index 30cb30271..f660cd286 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -1564,7 +1564,7 @@ namespace Game.Spells if (existingAura.GetSpellInfo().IsChanneled()) return true; - if (m_spellInfo.HasAttribute(SpellAttr3.StackForDiffCasters)) + if (m_spellInfo.HasAttribute(SpellAttr3.DotStackingRule)) return true; // check same periodic auras @@ -1820,6 +1820,14 @@ namespace Game.Spells } } + if (m_spellInfo.HasAttribute(SpellAttr3.OnlyProcOutdoors)) + if (!target.IsOutdoors()) + return 0; + + if (m_spellInfo.HasAttribute(SpellAttr3.OnlyProcOnCaster)) + if (target.GetGUID() != GetCasterGUID()) + return 0; + bool success = RandomHelper.randChance(CalcProcChance(procEntry, eventInfo)); SetLastProcAttemptTime(now); diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 8a2b923e2..c1ab9fda8 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -289,7 +289,7 @@ namespace Game.Spells if (noTargetFound) { - SendCastResult(m_spellInfo.Id == 51690 ? SpellCastResult.OutOfRange : SpellCastResult.BadTargets); + SendCastResult(SpellCastResult.BadImplicitTargets); Finish(false); return; } @@ -1558,9 +1558,9 @@ namespace Game.Spells break; } - if (m_spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers)) + if (m_spellInfo.HasAttribute(SpellAttr3.OnlyOnPlayer)) retMask &= GridMapTypeMask.Corpse | GridMapTypeMask.Player; - if (m_spellInfo.HasAttribute(SpellAttr3.OnlyTargetGhosts)) + if (m_spellInfo.HasAttribute(SpellAttr3.OnlyOnGhosts)) retMask &= GridMapTypeMask.Player; if (condList != null) @@ -2943,7 +2943,8 @@ namespace Game.Spells 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); + if (!m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs)) + Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null); // Call CreatureAI hook OnSpellCast Creature caster = m_originalCaster.ToCreature(); @@ -3209,7 +3210,8 @@ namespace Game.Spells } } - Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Finish, m_hitMask, this, null, null); + if (!m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs)) + Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Finish, m_hitMask, this, null, null); } void SendSpellCooldown() @@ -3354,7 +3356,8 @@ namespace Game.Spells if (creatureCaster != null) creatureCaster.ReleaseSpellFocus(this); - Unit.ProcSkillsAndAuras(unitCaster, null, new ProcFlagsInit(ProcFlags.CastEnded), new ProcFlagsInit(), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, this, null, null); + if (!m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs)) + Unit.ProcSkillsAndAuras(unitCaster, null, new ProcFlagsInit(ProcFlags.CastEnded), new ProcFlagsInit(), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, this, null, null); if (!ok) return; @@ -4229,7 +4232,7 @@ namespace Game.Spells resurrectRequest.ResurrectOffererVirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress(); resurrectRequest.Name = sentName; resurrectRequest.Sickness = m_caster.IsUnit() && !m_caster.IsTypeId(TypeId.Player); // "you'll be afflicted with resurrection sickness" - resurrectRequest.UseTimer = !m_spellInfo.HasAttribute(SpellAttr3.IgnoreResurrectionTimer); + resurrectRequest.UseTimer = !m_spellInfo.HasAttribute(SpellAttr3.NoResTimer); Pet pet = target.GetPet(); if (pet) @@ -4866,8 +4869,8 @@ namespace Game.Spells } // Spell casted only on Battleground - if (m_spellInfo.HasAttribute(SpellAttr3.Battleground) && m_caster.IsTypeId(TypeId.Player)) - if (!m_caster.ToPlayer().InBattleground()) + if (m_spellInfo.HasAttribute(SpellAttr3.OnlyBattlegrounds)) + if (!m_caster.GetMap().IsBattleground()) return SpellCastResult.OnlyBattlegrounds; // do not allow spells to be cast in arenas or rated Battlegrounds @@ -6783,7 +6786,7 @@ namespace Game.Spells }); // main hand weapon required - if (m_spellInfo.HasAttribute(SpellAttr3.MainHand)) + if (m_spellInfo.HasAttribute(SpellAttr3.RequiresMainHandWeapon)) { SpellCastResult mainHandResult = weaponCheck(WeaponAttackType.BaseAttack); if (mainHandResult != SpellCastResult.SpellCastOk) @@ -6791,7 +6794,7 @@ namespace Game.Spells } // offhand hand weapon required - if (m_spellInfo.HasAttribute(SpellAttr3.ReqOffhand)) + if (m_spellInfo.HasAttribute(SpellAttr3.RequiresOffHandWeapon)) { SpellCastResult offHandResult = weaponCheck(WeaponAttackType.OffAttack); if (offHandResult != SpellCastResult.SpellCastOk) @@ -8195,13 +8198,12 @@ namespace Game.Spells if ((MissCondition == SpellMissInfo.Immune || MissCondition == SpellMissInfo.Immune2) && spell.GetCaster().IsPlayer() && unit.IsPlayer() && spell.GetCaster().IsValidAttackTarget(unit, spell.GetSpellInfo())) unit.SetInCombatWith(spell.GetCaster().ToPlayer()); - _enablePVP = false; // need to check PvP state before spell effects, but act on it afterwards + // if target is flagged for pvp also flag caster if a player + _enablePVP = (MissCondition == SpellMissInfo.None || spell.m_spellInfo.HasAttribute(SpellAttr3.PvpEnabling)) + && unit.IsPvP() && spell.GetCaster().IsPlayer(); // need to check PvP state before spell effects, but act on it afterwards + if (_spellHitTarget) { - // if target is flagged for pvp also flag caster if a player - if (unit.IsPvP() && spell.GetCaster().IsPlayer()) - _enablePVP = true; // Decide on PvP flagging now, but act on it later. - SpellMissInfo missInfo = spell.PreprocessSpellHit(_spellHitTarget, this); if (missInfo != SpellMissInfo.None) { @@ -8276,8 +8278,9 @@ namespace Game.Spells ProcFlagsHit hitMask = ProcFlagsHit.None; // Spells with this flag cannot trigger if effect is cast on self - bool canEffectTrigger = !spell.m_spellInfo.HasAttribute(SpellAttr3.CantTriggerProc) && spell.unitTarget.CanProc() && - (spell.CanExecuteTriggersOnHit(EffectMask) || MissCondition == SpellMissInfo.Immune || MissCondition == SpellMissInfo.Immune2); + bool canEffectTrigger = (!spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs) || !spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressTargetProcs)) + && spell.unitTarget.CanProc() + && (spell.CanExecuteTriggersOnHit(EffectMask) || MissCondition == SpellMissInfo.Immune || MissCondition == SpellMissInfo.Immune2); // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now if (canEffectTrigger && !procAttacker && !procVictim) @@ -8440,6 +8443,12 @@ namespace Game.Spells // Do triggers for unit if (canEffectTrigger) { + if (spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressCasterProcs)) + procAttacker = new ProcFlagsInit(); + + if (spell.m_spellInfo.HasAttribute(SpellAttr3.SuppressTargetProcs)) + procVictim = new ProcFlagsInit(); + Unit.ProcSkillsAndAuras(caster, spell.unitTarget, procAttacker, procVictim, procSpellType, ProcFlagsSpellPhase.Hit, hitMask, spell, spellDamageInfo, healInfo); // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit) @@ -8465,7 +8474,7 @@ namespace Game.Spells if (unitCaster != null) unitCaster.AtTargetAttacked(unit, spell.m_spellInfo.HasInitialAggro()); - if (!unit.IsStandState()) + if (!spell.m_spellInfo.HasAttribute(SpellAttr3.DoNotTriggerTargetStand) && !unit.IsStandState()) unit.SetStandState(UnitStandStateType.Stand); } @@ -8508,10 +8517,10 @@ namespace Game.Spells // Needs to be called after dealing damage/healing to not remove breaking on damage auras spell.DoTriggersOnSpellHit(_spellHitTarget, EffectMask); - - if (_enablePVP) - spell.GetCaster().ToPlayer().UpdatePvP(true); } + + if (_enablePVP) + spell.GetCaster().ToPlayer().UpdatePvP(true); spell.spellAura = HitAura; spell.CallScriptAfterHitHandlers(); diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 7efe3a928..641c151a1 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -475,7 +475,7 @@ namespace Game.Spells public bool IsStackableOnOneSlotWithDifferentCasters() { // TODO: Re-verify meaning of SPELL_ATTR3_STACK_FOR_DIFF_CASTERS and update conditions here - return StackAmount > 1 && !IsChanneled() && !HasAttribute(SpellAttr3.StackForDiffCasters); + return StackAmount > 1 && !IsChanneled() && !HasAttribute(SpellAttr3.DotStackingRule); } public bool IsCooldownStartedOnEvent() @@ -489,12 +489,12 @@ namespace Game.Spells public bool IsDeathPersistent() { - return HasAttribute(SpellAttr3.DeathPersistent); + return HasAttribute(SpellAttr3.AllowAuraWhileDead); } public bool IsRequiringDeadTarget() { - return HasAttribute(SpellAttr3.OnlyTargetGhosts); + return HasAttribute(SpellAttr3.OnlyOnGhosts); } public bool IsAllowingDeadTarget() @@ -594,7 +594,7 @@ namespace Game.Spells switch (DmgClass) { case SpellDmgClass.Melee: - if (HasAttribute(SpellAttr3.ReqOffhand)) + if (HasAttribute(SpellAttr3.RequiresOffHandWeapon)) result = WeaponAttackType.OffAttack; else result = WeaponAttackType.BaseAttack; @@ -643,7 +643,7 @@ namespace Game.Spells bool IsAffectedBySpellMods() { - return !HasAttribute(SpellAttr3.NoDoneBonus); + return !HasAttribute(SpellAttr3.IgnoreCasterModifiers); } public bool IsAffectedBySpellMod(SpellModifier mod) @@ -1025,9 +1025,9 @@ namespace Game.Spells return SpellCastResult.TargetAffectingCombat; // only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts - if (HasAttribute(SpellAttr3.OnlyTargetGhosts) != unitTarget.HasAuraType(AuraType.Ghost)) + if (HasAttribute(SpellAttr3.OnlyOnGhosts) != unitTarget.HasAuraType(AuraType.Ghost)) { - if (HasAttribute(SpellAttr3.OnlyTargetGhosts)) + if (HasAttribute(SpellAttr3.OnlyOnGhosts)) return SpellCastResult.TargetNotGhost; else return SpellCastResult.BadTargets; @@ -1089,7 +1089,7 @@ namespace Game.Spells return SpellCastResult.SpellCastOk; // corpseOwner and unit specific target checks - if (HasAttribute(SpellAttr3.OnlyTargetPlayers) && !unitTarget.IsTypeId(TypeId.Player)) + if (HasAttribute(SpellAttr3.OnlyOnPlayer) && !unitTarget.IsTypeId(TypeId.Player)) return SpellCastResult.TargetNotPlayer; if (!IsAllowingDeadTarget() && !unitTarget.IsAlive()) @@ -2544,7 +2544,7 @@ namespace Game.Spells } } - if (!auraSpellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) + if (!auraSpellInfo.HasAttribute(SpellAttr3.AlwaysHit)) { AuraType auraName = auraSpellEffectInfo.ApplyAuraName; if (auraName != 0) @@ -2868,7 +2868,7 @@ namespace Game.Spells else { WeaponAttackType slot = WeaponAttackType.BaseAttack; - if (!HasAttribute(SpellAttr3.MainHand) && HasAttribute(SpellAttr3.ReqOffhand)) + if (!HasAttribute(SpellAttr3.RequiresMainHandWeapon) && HasAttribute(SpellAttr3.RequiresOffHandWeapon)) slot = WeaponAttackType.OffAttack; speed = unitCaster.GetBaseAttackTime(slot); @@ -3175,7 +3175,7 @@ namespace Game.Spells return this; // Client ignores spell with these attributes (sub_53D9D0) - if (HasAttribute(SpellAttr0.AuraIsDebuff) || HasAttribute(SpellAttr2.AllowLowLevelBuff) || HasAttribute(SpellAttr3.DrainSoul)) + if (HasAttribute(SpellAttr0.AuraIsDebuff) || HasAttribute(SpellAttr2.AllowLowLevelBuff) || HasAttribute(SpellAttr3.OnlyProcOnCaster)) return this; bool needRankSelection = false; diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index efa728697..013e01e98 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -2734,7 +2734,7 @@ namespace Game.Entities } // spells ignoring hit result should not be binary - if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) + if (!spellInfo.HasAttribute(SpellAttr3.AlwaysHit)) { bool setFlag = false; foreach (var spellEffectInfo in spellInfo.GetEffects()) @@ -3185,12 +3185,6 @@ namespace Game.Entities }); }); - // Execute - ApplySpellFix(new[] { 5308 }, spellInfo => - { - spellInfo.AttributesEx3 |= SpellAttr3.CantTriggerProc; - }); - ApplySpellFix(new[] { 31347, // Doom 36327, // Shoot Arcane Explosion Arrow @@ -3340,7 +3334,7 @@ namespace Game.Entities // Oscillation Field ApplySpellFix(new[] { 37408 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.StackForDiffCasters; + spellInfo.AttributesEx3 |= SpellAttr3.DotStackingRule; }); // Crafty's Ultra-Advanced Proto-Typical Shortening Blaster @@ -3397,12 +3391,6 @@ namespace Game.Entities }); }); - // Vampiric Embrace - ApplySpellFix(new[] { 15290 }, spellInfo => - { - spellInfo.AttributesEx3 |= SpellAttr3.NoInitialAggro; - }); - // Earthbind Totem (instant pulse) ApplySpellFix(new[] { 6474 }, spellInfo => { @@ -3475,7 +3463,7 @@ namespace Game.Entities // Paralyze ApplySpellFix(new[] { 48278 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.StackForDiffCasters; + spellInfo.AttributesEx3 |= SpellAttr3.DotStackingRule; }); ApplySpellFix(new[] { @@ -3685,7 +3673,7 @@ namespace Game.Entities 64381 // Strength of the Pack (Auriaya) }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.StackForDiffCasters; + spellInfo.AttributesEx3 |= SpellAttr3.DotStackingRule; }); ApplySpellFix(new[] { @@ -3845,13 +3833,7 @@ namespace Game.Entities // Shadow's Fate ApplySpellFix(new[] { 71169 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.StackForDiffCasters; - }); - - // Lock Players and Tap Chest - ApplySpellFix(new[] { 72347 }, spellInfo => - { - spellInfo.AttributesEx3 &= ~SpellAttr3.NoInitialAggro; + spellInfo.AttributesEx3 |= SpellAttr3.DotStackingRule; }); // Resistant Skin (Deathbringer Saurfang adds) @@ -3918,7 +3900,7 @@ namespace Game.Entities // Empowered Flare (Blood Prince Council) ApplySpellFix(new[] { 71708 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.NoDoneBonus; + spellInfo.AttributesEx3 |= SpellAttr3.IgnoreCasterModifiers; }); // Swarming Shadows @@ -3930,7 +3912,7 @@ namespace Game.Entities // Corruption ApplySpellFix(new[] { 70602 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.StackForDiffCasters; + spellInfo.AttributesEx3 |= SpellAttr3.DotStackingRule; }); // Column of Frost (visual marker) @@ -3974,7 +3956,7 @@ namespace Game.Entities // Chilled to the Bone ApplySpellFix(new[] { 70106 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.NoDoneBonus; + spellInfo.AttributesEx3 |= SpellAttr3.IgnoreCasterModifiers; spellInfo.AttributesEx6 |= SpellAttr6.IgnoreCasterDamageModifiers; }); @@ -4024,7 +4006,7 @@ namespace Game.Entities // Harvest Soul ApplySpellFix(new[] { 73655 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.NoDoneBonus; + spellInfo.AttributesEx3 |= SpellAttr3.IgnoreCasterModifiers; }); // Summon Shadow Trap @@ -4194,12 +4176,6 @@ namespace Game.Entities spellInfo.Stances = 1ul << ((int)ShapeShiftForm.TreeOfLife - 1); }); - // Feral Charge (Cat Form) - ApplySpellFix(new[] { 49376 }, spellInfo => - { - spellInfo.AttributesEx3 &= ~SpellAttr3.CantTriggerProc; - }); - // Gaze of Occu'thar ApplySpellFix(new[] { 96942 }, spellInfo => { @@ -4254,13 +4230,13 @@ namespace Game.Entities // Baron Rivendare (Stratholme) - Unholy Aura ApplySpellFix(new [] { 17466, 17467 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.NoInitialAggro; + spellInfo.AttributesEx2 |= SpellAttr2.NoInitialThreat; }); // Spore - Spore Visual ApplySpellFix(new[] { 42525 }, spellInfo => { - spellInfo.AttributesEx3 |= SpellAttr3.DeathPersistent; + spellInfo.AttributesEx3 |= SpellAttr3.AllowAuraWhileDead; spellInfo.AttributesEx2 |= SpellAttr2.AllowDeadTarget; });