diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index aad4ef8d4..ad54216b9 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -1618,38 +1618,38 @@ namespace Framework.Constants } public enum SpellAttr1 : uint { - DismissPet = 0x01, // 0 For Spells Without This Flag Client Doesn'T Allow To Summon Pet If Caster Has A Pet - DrainAllPower = 0x02, // 1 Use All Power (Only Paladin Lay Of Hands And Bunyanize) - Channeled1 = 0x04, // 2 Clientside Checked? Cancelable? - CantBeRedirected = 0x08, // 3 - Unk4 = 0x10, // 4 Stealth And Whirlwind - NotBreakStealth = 0x20, // 5 Not Break Stealth - Channeled2 = 0x40, // 6 - CantBeReflected = 0x80, // 7 - CantTargetInCombat = 0x100, // 8 Can Target Only Out Of Combat Units - MeleeCombatStart = 0x200, // 9 Player Starts Melee Combat After This Spell Is Cast - NoThreat = 0x400, // 10 No Generates Threat On Cast 100% (Old NoInitialAggro) - DontRefreshDurationOnRecast = 0x800, // 11 aura will not refresh its duration when recast - IsPickpocket = 0x1000, // 12 Pickpocket - Farsight = 0x2000, // 13 Client Removes Farsight On Aura Loss - ChannelTrackTarget = 0x4000, // 14 Client Automatically Forces Player To Face Target When Channeling - DispelAurasOnImmunity = 0x8000, // 15 Remove Auras On Immunity - UnaffectedBySchoolImmune = 0x10000, // 16 On Immuniy - UnautocastableByPet = 0x20000, // 17 - PreventsAnim = 0x40000, // 18 Prevents Anim DESCRIPTION NYI, auras apply UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT - CantTargetSelf = 0x80000, // 19 - ReqComboPoints1 = 0x100000, // 20 Req Combo Points On Target - Unk21 = 0x200000, // 21 - ReqComboPoints2 = 0x400000, // 22 Req Combo Points On Target - Unk23 = 0x800000, // 23 - IsFishing = 0x1000000, // 24 Only Fishing Spells - Unk25 = 0x2000000, // 25 - Unk26 = 0x4000000, // 26 Works Correctly With [Target=Focus] And [Target=Mouseover] Macros? - Unk27 = 0x8000000, // 27 Melee Spell? - DontDisplayInAuraBar = 0x10000000, // 28 Client Doesn'T Display These Spells In Aura Bar - ChannelDisplaySpellName = 0x20000000, // 29 Spell Name Is Displayed In Cast Bar Instead Of 'Channeling' Text - EnableAtDodge = 0x40000000, // 30 Overpower - CastWhenLearned = 0x80000000 // 31 + DismissPetFirst = 0x01, // Dismiss Pet First Description Without This Attribute, Summoning Spells Will Fail If Caster Already Has A Pet + UseAllMana = 0x02, // Use All Mana Description Ignores Listed Power Cost And Drains Entire Pool Instead + IsChannelled = 0x04, // Is Channelled Description Both "Channeled" Attributes Have Identical Handling In Server & Client + NoRedirection = 0x08, // No Redirection Description Spell Will Not Be Attracted By SpellMagnet Auras (Grounding Totem) + NoSkillIncrease = 0x10, // No Skill Increase + AllowWhileStealthed = 0x20, // Allow While Stealthed + IsSelfChannelled = 0x40, // Is Self Channelled Description Both "Channeled" Attributes Have Identical Handling In Server & Client + NoReflection = 0x80, // No Reflection Description Spell Will Pierce Through Spell Reflection And Similar + OnlyPeacefulTargets = 0x100, // Only Peaceful Targets Description Target Cannot Be In Combat + InitiatesCombatEnablesAutoAttack = 0x200, // Initiates Combat (Enables Auto-Attack) (Client Only) Description Caster Will Begin Auto-Attacking The Target On Cast + NoThreat = 0x400, // Does Not Generate Threat Description Also Does Not Cause Target To Engage + AuraUnique = 0x800, // Aura Unique Description Aura Will Not Refresh Its Duration When Recast + FailureBreaksStealth = 0x1000, // Failure Breaks Stealth + ToggleFarSight = 0x2000, // Toggle Far Sight (Client Only) + TrackTargetInChannel = 0x4000, // Track Target In Channel Description While Channeling, Adjust Facing To Face Target + ImmunityPurgesEffect = 0x8000, // Immunity Purges Effect Description For Immunity Spells, Cancel All Auras That This Spell Would Make You Immune To When The Spell Is Applied + ImmunityToHostileAndFriendlyEffects = 0x10000, /*Wrong Impl*/ // Immunity To Hostile & Friendly Effects Description Will Not Pierce Divine Shield, Ice Block And Other Full Invulnerabilities + NoAutocastAi = 0x20000, // No Autocast (Ai) + PreventsAnim = 0x40000, /*Nyi*/ // Prevents Anim Description Auras Apply UnitFlagPreventEmotesFromChatText + ExcludeCaster = 0x80000, // Exclude Caster + FinishingMoveDamage = 0x100000, // Finishing Move - Damage + ThreatOnlyOnMiss = 0x200000, /*Nyi*/ // Threat Only On Miss + FinishingMoveDuration = 0x400000, // Finishing Move - Duration + IgnoreOwnersDeath = 0x800000, /*Nyi*/ // Ignore Owner'S Death + SpecialSkillup = 0x1000000, // Special Skillup + AuraStaysAfterCombat = 0x2000000, // Aura Stays After Combat + RequireAllTargets = 0x4000000, /*Nyi, Unk*/ // Require All Targets + DiscountPowerOnMiss = 0x8000000, // Discount Power On Miss + NoAuraIcon = 0x10000000, // No Aura Icon (Client Only) + NameInChannelBar = 0x20000000, // Name In Channel Bar (Client Only) + DispelAllStacks = 0x40000000, // Dispel All Stacks + CastWhenLearned = 0x80000000 // Cast When Learned } public enum SpellAttr2 : uint { diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 9236ae5d7..4a516d225 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -2750,7 +2750,7 @@ namespace Game.Entities public Unit GetMagicHitRedirectTarget(Unit victim, SpellInfo spellInfo) { // Patch 1.2 notes: Spell Reflection no longer reflects abilities - if (spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr1.CantBeRedirected) || spellInfo.HasAttribute(SpellAttr0.NoImmunities)) + if (spellInfo.HasAttribute(SpellAttr0.IsAbility) || spellInfo.HasAttribute(SpellAttr1.NoRedirection) || spellInfo.HasAttribute(SpellAttr0.NoImmunities)) return victim; var magnetAuras = victim.GetAuraEffectsByType(AuraType.SpellMagnet); diff --git a/Source/Game/Entities/Player/Player.Spells.cs b/Source/Game/Entities/Player/Player.Spells.cs index e865f6d7c..e9c1b8a6e 100644 --- a/Source/Game/Entities/Player/Player.Spells.cs +++ b/Source/Game/Entities/Player/Player.Spells.cs @@ -1245,11 +1245,14 @@ namespace Game.Entities } } - public bool UpdateCraftSkill(uint spellid) + public bool UpdateCraftSkill(SpellInfo spellInfo) { - Log.outDebug(LogFilter.Player, "UpdateCraftSkill spellid {0}", spellid); + if (spellInfo.HasAttribute(SpellAttr1.NoSkillIncrease)) + return false; - var bounds = Global.SpellMgr.GetSkillLineAbilityMapBounds(spellid); + Log.outDebug(LogFilter.Player, "UpdateCraftSkill spellid {0}", spellInfo.Id); + + var bounds = Global.SpellMgr.GetSkillLineAbilityMapBounds(spellInfo.Id); foreach (var _spell_idx in bounds) { @@ -1258,10 +1261,9 @@ namespace Game.Entities uint SkillValue = GetPureSkillValue((SkillType)_spell_idx.SkillupSkillLineID); // Alchemy Discoveries here - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(spellid, Difficulty.None); - if (spellEntry != null && spellEntry.Mechanic == Mechanics.Discovery) + if (spellInfo != null && spellInfo.Mechanic == Mechanics.Discovery) { - uint discoveredSpell = SkillDiscovery.GetSkillDiscoverySpell(_spell_idx.SkillupSkillLineID, spellid, this); + uint discoveredSpell = SkillDiscovery.GetSkillDiscoverySpell(_spell_idx.SkillupSkillLineID, spellInfo.Id, this); if (discoveredSpell != 0) LearnSpell(discoveredSpell, false); } diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index d08d31ed5..6143dca87 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1382,7 +1382,7 @@ namespace Game.Entities if (spellInfo.HasAttribute(SpellAttr0.NoImmunities) && spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) return false; - if (spellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + if (spellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) return false; uint schoolMask = (uint)spellInfo.GetSchoolMask(); @@ -2156,7 +2156,27 @@ namespace Game.Entities // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle // don't remove clone caster on evade (to be verified) - RemoveAllAurasExceptType(AuraType.ControlVehicle, AuraType.CloneCaster); + bool evadeAuraCheck(Aura aura) + { + if (aura.HasEffectType(AuraType.ControlVehicle)) + return false; + + if (aura.HasEffectType(AuraType.CloneCaster)) + return false; + + if (aura.GetSpellInfo().HasAttribute(SpellAttr1.AuraStaysAfterCombat)) + return false; + + return true; + } + + bool evadeAuraApplicationCheck(AuraApplication aurApp) + { + return evadeAuraCheck(aurApp.GetBase()); + } + + RemoveAppliedAuras(evadeAuraApplicationCheck); + RemoveOwnedAuras(evadeAuraCheck); } public void RemoveAllAurasOnDeath() @@ -2895,7 +2915,7 @@ namespace Game.Entities } } } - public void RemoveAurasDueToSpellBySteal(uint spellId, ObjectGuid casterGUID, WorldObject stealer) + public void RemoveAurasDueToSpellBySteal(uint spellId, ObjectGuid casterGUID, WorldObject stealer, int stolenCharges = 1) { var range = m_ownedAuras.LookupByKey(spellId); foreach (var aura in range) @@ -2935,9 +2955,9 @@ namespace Game.Entities if (oldAura != null) { if (stealCharge) - oldAura.ModCharges(1); + oldAura.ModCharges(stolenCharges); else - oldAura.ModStackAmount(1); + oldAura.ModStackAmount(stolenCharges); oldAura.SetDuration((int)dur); } else @@ -2962,16 +2982,16 @@ namespace Game.Entities caster.GetSingleCastAuras().Add(aura); } // FIXME: using aura.GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate - newAura.SetLoadedState(aura.GetMaxDuration(), (int)dur, stealCharge ? 1 : aura.GetCharges(), 1, recalculateMask, damage); + newAura.SetLoadedState(aura.GetMaxDuration(), (int)dur, stealCharge ? stolenCharges : aura.GetCharges(), (byte)stolenCharges, recalculateMask, damage); newAura.ApplyForTargets(); } } } if (stealCharge) - aura.ModCharges(-1, AuraRemoveMode.EnemySpell); + aura.ModCharges(-stolenCharges, AuraRemoveMode.EnemySpell); else - aura.ModStackAmount(-1, AuraRemoveMode.EnemySpell); + aura.ModStackAmount(-stolenCharges, AuraRemoveMode.EnemySpell); return; } diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index c950e5847..bb563d6be 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -956,7 +956,7 @@ namespace Game.Spells return true; } - bool refresh = stackAmount >= GetStackAmount() && (m_spellInfo.StackAmount != 0 || !m_spellInfo.HasAttribute(SpellAttr1.DontRefreshDurationOnRecast)); + bool refresh = stackAmount >= GetStackAmount() && (m_spellInfo.StackAmount != 0 || !m_spellInfo.HasAttribute(SpellAttr1.AuraUnique)); // Update stack amount SetStackAmount((byte)stackAmount); diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 260cea85e..fba2c7d7e 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -515,7 +515,7 @@ namespace Game.Spells // Update serverside orientation of tracking channeled auras on periodic update ticks // exclude players because can turn during channeling and shouldn't desync orientation client/server - if (caster != null && !caster.IsPlayer() && m_spellInfo.IsChanneled() && m_spellInfo.HasAttribute(SpellAttr1.ChannelTrackTarget) && caster.m_unitData.ChannelObjects.Size() != 0) + if (caster != null && !caster.IsPlayer() && m_spellInfo.IsChanneled() && m_spellInfo.HasAttribute(SpellAttr1.TrackTargetInChannel) && caster.m_unitData.ChannelObjects.Size() != 0) { ObjectGuid channelGuid = caster.m_unitData.ChannelObjects[0]; if (channelGuid != caster.GetGUID()) @@ -2836,7 +2836,7 @@ namespace Game.Spells target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); // remove all flag auras (they are positive, but they must be removed when you are immune) - if (GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity) + if (GetSpellInfo().HasAttribute(SpellAttr1.ImmunityPurgesEffect) && GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield)) target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); } diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index a8cd1b613..e5c11023e 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -106,7 +106,7 @@ namespace Game.Spells // Determine if spell can be reflected back to the caster // Patch 1.2 notes: Spell Reflection no longer reflects abilities m_canReflect = caster.IsUnit() && m_spellInfo.DmgClass == SpellDmgClass.Magic && !m_spellInfo.HasAttribute(SpellAttr0.IsAbility) - && !m_spellInfo.HasAttribute(SpellAttr1.CantBeReflected) && !m_spellInfo.HasAttribute(SpellAttr0.NoImmunities) + && !m_spellInfo.HasAttribute(SpellAttr1.NoReflection) && !m_spellInfo.HasAttribute(SpellAttr0.NoImmunities) && !m_spellInfo.IsPassive(); CleanupTargetList(); @@ -2753,7 +2753,7 @@ namespace Game.Spells Unit unitCaster = m_caster.ToUnit(); if (unitCaster != null) { - if (m_spellInfo.HasAttribute(SpellAttr1.DismissPet)) + if (m_spellInfo.HasAttribute(SpellAttr1.DismissPetFirst)) { Creature pet = ObjectAccessor.GetCreature(m_caster, unitCaster.GetPetGUID()); if (pet != null) @@ -4134,37 +4134,46 @@ namespace Game.Spells m_timer = (int)duration; - uint channelAuraMask = 0; - uint explicitTargetEffectMask = 0xFFFFFFFF; - // if there is an explicit target, only add channel objects from effects that also hit ut - if (!m_targets.GetUnitTargetGUID().IsEmpty()) + if (!m_targets.HasDst()) { - var explicitTarget = m_UniqueTargetInfo.Find(target => target.TargetGUID == m_targets.GetUnitTargetGUID()); - if (explicitTarget != null) - explicitTargetEffectMask = explicitTarget.EffectMask; - } - - foreach (var spellEffectInfo in m_spellInfo.GetEffects()) - if (spellEffectInfo.Effect == SpellEffectName.ApplyAura && (explicitTargetEffectMask & (1u << (int)spellEffectInfo.EffectIndex)) != 0) - channelAuraMask |= 1u << (int)spellEffectInfo.EffectIndex; - - foreach (TargetInfo target in m_UniqueTargetInfo) - { - if ((target.EffectMask & channelAuraMask) != 0) - unitCaster.AddChannelObject(target.TargetGUID); - - if (m_UniqueTargetInfo.Count == 1 && m_UniqueGOTargetInfo.Empty()) + uint channelAuraMask = 0; + uint explicitTargetEffectMask = 0xFFFFFFFF; + // if there is an explicit target, only add channel objects from effects that also hit ut + if (!m_targets.GetUnitTargetGUID().IsEmpty()) { - Creature creatureCaster = unitCaster.ToCreature(); - if (creatureCaster != null) - if (!creatureCaster.HasSpellFocus(this)) - creatureCaster.SetSpellFocus(this, Global.ObjAccessor.GetWorldObject(creatureCaster, target.TargetGUID)); + var explicitTarget = m_UniqueTargetInfo.Find(target => target.TargetGUID == m_targets.GetUnitTargetGUID()); + if (explicitTarget != null) + explicitTargetEffectMask = explicitTarget.EffectMask; } - } - foreach (GOTargetInfo target in m_UniqueGOTargetInfo) - if ((target.EffectMask & channelAuraMask) != 0) + foreach (var spellEffectInfo in m_spellInfo.GetEffects()) + if (spellEffectInfo.Effect == SpellEffectName.ApplyAura && (explicitTargetEffectMask & (1u << (int)spellEffectInfo.EffectIndex)) != 0) + channelAuraMask |= 1u << (int)spellEffectInfo.EffectIndex; + + foreach (TargetInfo target in m_UniqueTargetInfo) + { + if ((target.EffectMask & channelAuraMask) == 0) + continue; + + SpellAttr1 requiredAttribute = target.TargetGUID != unitCaster.GetGUID() ? SpellAttr1.IsChannelled : SpellAttr1.IsSelfChannelled; + if (!m_spellInfo.HasAttribute(requiredAttribute)) + continue; + unitCaster.AddChannelObject(target.TargetGUID); + } + + foreach (GOTargetInfo target in m_UniqueGOTargetInfo) + if ((target.EffectMask & channelAuraMask) != 0) + unitCaster.AddChannelObject(target.TargetGUID); + } + else if (m_spellInfo.HasAttribute(SpellAttr1.IsSelfChannelled)) + unitCaster.AddChannelObject(unitCaster.GetGUID()); + + Creature creatureCaster = unitCaster.ToCreature(); + if (creatureCaster != null) + if (unitCaster.m_unitData.ChannelObjects.Size() == 1 && unitCaster.m_unitData.ChannelObjects[0].IsUnit()) + if (!creatureCaster.HasSpellFocus(this)) + creatureCaster.SetSpellFocus(this, Global.ObjAccessor.GetWorldObject(creatureCaster, unitCaster.m_unitData.ChannelObjects[0])); unitCaster.SetChannelSpellId(m_spellInfo.Id); unitCaster.SetChannelVisual(m_SpellVisual); @@ -4287,7 +4296,7 @@ namespace Game.Spells bool hit = true; if (unitCaster.IsTypeId(TypeId.Player)) { - if (cost.Power == PowerType.Rage || cost.Power == PowerType.Energy || cost.Power == PowerType.Runes) + if (m_spellInfo.HasAttribute(SpellAttr1.DiscountPowerOnMiss)) { ObjectGuid targetGUID = m_targets.GetUnitTargetGUID(); if (!targetGUID.IsEmpty()) @@ -4556,7 +4565,7 @@ namespace Game.Spells { if (m_spellInfo.HasAttribute(SpellAttr0.UsesRangedSlot) || m_spellInfo.IsNextMeleeSwingSpell() - || m_spellInfo.HasAttribute(SpellAttr1.MeleeCombatStart) + || m_spellInfo.HasAttribute(SpellAttr1.InitiatesCombatEnablesAutoAttack) || m_spellInfo.HasAttribute(SpellAttr2.Unk20) || m_spellInfo.HasEffect(SpellEffectName.Attack) || m_spellInfo.HasEffect(SpellEffectName.NormalizedWeaponDmg) @@ -5205,7 +5214,7 @@ namespace Game.Spells switch (SummonProperties.Control) { case SummonCategory.Pet: - if (!m_spellInfo.HasAttribute(SpellAttr1.DismissPet) && !unitCaster.GetPetGUID().IsEmpty()) + if (!m_spellInfo.HasAttribute(SpellAttr1.DismissPetFirst) && !unitCaster.GetPetGUID().IsEmpty()) return SpellCastResult.AlreadyHaveSummon; goto case SummonCategory.Puppet; case SummonCategory.Puppet: @@ -5221,7 +5230,7 @@ namespace Game.Spells { if (!m_targets.GetUnitTarget().IsTypeId(TypeId.Player)) return SpellCastResult.BadTargets; - if (!m_spellInfo.HasAttribute(SpellAttr1.DismissPet) && !m_targets.GetUnitTarget().GetPetGUID().IsEmpty()) + if (!m_spellInfo.HasAttribute(SpellAttr1.DismissPetFirst) && !m_targets.GetUnitTarget().GetPetGUID().IsEmpty()) return SpellCastResult.AlreadyHaveSummon; } break; @@ -5246,7 +5255,7 @@ namespace Game.Spells } } } - else if (!m_spellInfo.HasAttribute(SpellAttr1.DismissPet)) + else if (!m_spellInfo.HasAttribute(SpellAttr1.DismissPetFirst)) return SpellCastResult.AlreadyHaveSummon; } @@ -5581,7 +5590,7 @@ namespace Game.Spells if (spellEffectInfo.ApplyAuraName == AuraType.ModCharm || spellEffectInfo.ApplyAuraName == AuraType.ModPossess) { - if (!m_spellInfo.HasAttribute(SpellAttr1.DismissPet) && !unitCaster1.GetPetGUID().IsEmpty()) + if (!m_spellInfo.HasAttribute(SpellAttr1.DismissPetFirst) && !unitCaster1.GetPetGUID().IsEmpty()) return SpellCastResult.AlreadyHaveSummon; if (!unitCaster1.GetCharmedGUID().IsEmpty()) @@ -7751,7 +7760,7 @@ namespace Game.Spells public bool IsTriggered() { return _triggeredCastFlags.HasAnyFlag(TriggerCastFlags.FullMask); } public bool IsTriggeredByAura(SpellInfo auraSpellInfo) { return (auraSpellInfo == m_triggeredByAuraSpell); } public bool IsIgnoringCooldowns() { return _triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreSpellAndCategoryCD); } - public bool IsFocusDisabled() { return _triggeredCastFlags.HasFlag(TriggerCastFlags.IgnoreSetFacing) || (m_spellInfo.IsChanneled() && !m_spellInfo.HasAttribute(SpellAttr1.ChannelTrackTarget)); } + public bool IsFocusDisabled() { return _triggeredCastFlags.HasFlag(TriggerCastFlags.IgnoreSetFacing) || (m_spellInfo.IsChanneled() && !m_spellInfo.HasAttribute(SpellAttr1.TrackTargetInChannel)); } public bool IsProcDisabled() { return _triggeredCastFlags.HasAnyFlag(TriggerCastFlags.DisallowProcEvents); } public bool IsChannelActive() { return m_caster.IsUnit() && m_caster.ToUnit().GetChannelSpellId() != 0; } diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 060121211..56b73fd62 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -992,7 +992,7 @@ namespace Game.Spells } // we succeeded in creating at least one item, so a levelup is possible - player.UpdateCraftSkill(m_spellInfo.Id); + player.UpdateCraftSkill(m_spellInfo); } } @@ -1023,7 +1023,7 @@ namespace Game.Spells if (m_spellInfo.IsLootCrafting()) { player.AutoStoreLoot(m_spellInfo.Id, LootStorage.Spell, context, false, true); - player.UpdateCraftSkill(m_spellInfo.Id); + player.UpdateCraftSkill(m_spellInfo); } else // If there's no random loot entries for this spell, pick the item associated with this spell { @@ -1807,12 +1807,16 @@ namespace Game.Spells return false; }); + byte dispelledCharges = 1; + if (dispelableAura.GetAura().GetSpellInfo().HasAttribute(SpellAttr1.DispelAllStacks)) + dispelledCharges = dispelableAura.GetDispelCharges(); + if (successAura == null) - successList.Add(new DispelableAura(dispelableAura.GetAura(), 0, 1)); + successList.Add(new DispelableAura(dispelableAura.GetAura(), 0, dispelledCharges)); else successAura.IncrementCharges(); - if (!dispelableAura.DecrementCharge()) + if (!dispelableAura.DecrementCharge(dispelledCharges)) { --remaining; dispelList[remaining] = dispelableAura; @@ -2037,7 +2041,7 @@ namespace Game.Spells { // do not increase skill if vellum used if (!(m_CastItem && m_CastItem.GetTemplate().HasFlag(ItemFlags.NoReagentCost))) - player.UpdateCraftSkill(m_spellInfo.Id); + player.UpdateCraftSkill(m_spellInfo); uint enchant_id = (uint)effectInfo.MiscValue; if (enchant_id == 0) @@ -3154,7 +3158,7 @@ namespace Game.Spells Player caster = m_caster.ToPlayer(); if (caster != null) { - caster.UpdateCraftSkill(m_spellInfo.Id); + caster.UpdateCraftSkill(m_spellInfo); caster.SendLoot(itemTarget.GetGUID(), LootType.Disenchanting); } @@ -4359,7 +4363,7 @@ namespace Game.Spells int remaining = stealList.Count; // Ok if exist some buffs for dispel try dispel it - List> successList = new(); + List> successList = new(); DispelFailed dispelFailed = new(); dispelFailed.CasterGUID = m_caster.GetGUID(); @@ -4374,8 +4378,12 @@ namespace Game.Spells if (dispelableAura.RollDispel()) { - successList.Add(Tuple.Create(dispelableAura.GetAura().GetId(), dispelableAura.GetAura().GetCasterGUID())); - if (!dispelableAura.DecrementCharge()) + byte stolenCharges = 1; + if (dispelableAura.GetAura().GetSpellInfo().HasAttribute(SpellAttr1.DispelAllStacks)) + stolenCharges = dispelableAura.GetDispelCharges(); + + successList.Add(Tuple.Create(dispelableAura.GetAura().GetId(), dispelableAura.GetAura().GetCasterGUID(), (int)stolenCharges)); + if (!dispelableAura.DecrementCharge(stolenCharges)) { --remaining; stealList[remaining] = dispelableAura; @@ -4402,13 +4410,13 @@ namespace Game.Spells spellDispellLog.CasterGUID = m_caster.GetGUID(); spellDispellLog.DispelledBySpellID = m_spellInfo.Id; - foreach (var dispell in successList) + foreach (var (spellId, auraCaster, stolenCharges) in successList) { var dispellData = new SpellDispellData(); - dispellData.SpellID = dispell.Item1; + dispellData.SpellID = spellId; dispellData.Harmful = false; // TODO: use me - unitTarget.RemoveAurasDueToSpellBySteal(dispell.Item1, dispell.Item2, m_caster); + unitTarget.RemoveAurasDueToSpellBySteal(spellId, auraCaster, m_caster, stolenCharges); spellDispellLog.DispellData.Add(dispellData); } @@ -5670,12 +5678,12 @@ namespace Game.Spells ++_charges; } - public bool DecrementCharge() + public bool DecrementCharge(byte charges) { if (_charges == 0) return false; - --_charges; + _charges -= charges; return _charges > 0; } diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index a9f961e4a..434814c26 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -431,7 +431,7 @@ namespace Game.Spells { if (IsPassive()) return false; - if (HasAttribute(SpellAttr1.UnautocastableByPet)) + if (HasAttribute(SpellAttr1.NoAutocastAi)) return false; return true; } @@ -548,7 +548,7 @@ namespace Game.Spells public bool IsChanneled() { - return HasAttribute(SpellAttr1.Channeled1 | SpellAttr1.Channeled2); + return HasAttribute(SpellAttr1.IsChannelled | SpellAttr1.IsSelfChannelled); } public bool IsMoveAllowedChannel() @@ -558,7 +558,7 @@ namespace Game.Spells public bool NeedsComboPoints() { - return HasAttribute(SpellAttr1.ReqComboPoints1 | SpellAttr1.ReqComboPoints2); + return HasAttribute(SpellAttr1.FinishingMoveDamage | SpellAttr1.FinishingMoveDuration); } public bool IsNextMeleeSwingSpell() @@ -568,7 +568,7 @@ namespace Game.Spells public bool IsBreakingStealth() { - return !HasAttribute(SpellAttr1.NotBreakStealth); + return !HasAttribute(SpellAttr1.AllowWhileStealthed); } public bool IsRangedWeaponSpell() @@ -689,7 +689,7 @@ namespace Game.Spells return true; // these spells (Cyclone for example) can pierce all... - if (HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + if (HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) || HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) { // ...but not these (Divine shield, Ice block, Cyclone and Banish for example) if (auraSpellInfo.Mechanic != Mechanics.ImmuneShield && @@ -699,7 +699,7 @@ namespace Game.Spells } // Dispels other auras on immunity, check if this spell makes the unit immune to aura - if (HasAttribute(SpellAttr1.DispelAurasOnImmunity) && CanSpellProvideImmunityAgainstAura(auraSpellInfo)) + if (HasAttribute(SpellAttr1.ImmunityPurgesEffect) && CanSpellProvideImmunityAgainstAura(auraSpellInfo)) return true; return false; @@ -716,7 +716,7 @@ namespace Game.Spells return true; // These auras (Cyclone for example) are not dispelable - if ((auraSpellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) && auraSpellInfo.Mechanic != Mechanics.None) + if ((auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && auraSpellInfo.Mechanic != Mechanics.None) || auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) return false; @@ -1013,7 +1013,7 @@ namespace Game.Spells public SpellCastResult CheckTarget(WorldObject caster, WorldObject target, bool Implicit = true) { - if (HasAttribute(SpellAttr1.CantTargetSelf) && caster == target) + if (HasAttribute(SpellAttr1.ExcludeCaster) && caster == target) return SpellCastResult.BadTargets; // check visibility - ignore stealth for implicit (area) targets @@ -1026,7 +1026,7 @@ namespace Game.Spells if (unitTarget != null) { // spells cannot be cast if target has a pet in combat either - if (HasAttribute(SpellAttr1.CantTargetInCombat) && (unitTarget.IsInCombat() || unitTarget.HasUnitFlag(UnitFlags.PetInCombat))) + if (HasAttribute(SpellAttr1.OnlyPeacefulTargets) && (unitTarget.IsInCombat() || unitTarget.HasUnitFlag(UnitFlags.PetInCombat))) return SpellCastResult.TargetAffectingCombat; // only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts @@ -2425,7 +2425,7 @@ namespace Game.Spells { target.ApplySpellImmune(Id, SpellImmunity.School, schoolImmunity, apply); - if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + if (apply && HasAttribute(SpellAttr1.ImmunityPurgesEffect)) { target.RemoveAppliedAuras(aurApp => { @@ -2449,7 +2449,7 @@ namespace Game.Spells if (Convert.ToBoolean(mechanicImmunity & (1 << (int)i))) target.ApplySpellImmune(Id, SpellImmunity.Mechanic, i, apply); - if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + if (apply && HasAttribute(SpellAttr1.ImmunityPurgesEffect)) { // exception for purely snare mechanic (eg. hands of freedom)! if (mechanicImmunity == (1 << (int)Mechanics.Snare)) @@ -2464,7 +2464,7 @@ namespace Game.Spells { target.ApplySpellImmune(Id, SpellImmunity.Dispel, dispelImmunity, apply); - if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + if (apply && HasAttribute(SpellAttr1.ImmunityPurgesEffect)) { target.RemoveAppliedAuras(aurApp => { @@ -2489,7 +2489,7 @@ namespace Game.Spells foreach (AuraType auraType in immuneInfo.AuraTypeImmune) { target.ApplySpellImmune(Id, SpellImmunity.State, auraType, apply); - if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + if (apply && HasAttribute(SpellAttr1.ImmunityPurgesEffect)) target.RemoveAurasByType(auraType); } @@ -2509,7 +2509,7 @@ namespace Game.Spells ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo(); - if (!auraSpellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + if (!auraSpellInfo.HasAttribute(SpellAttr1.ImmunityToHostileAndFriendlyEffects) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) { uint schoolImmunity = immuneInfo.SchoolImmuneMask; if (schoolImmunity != 0) @@ -2584,7 +2584,7 @@ namespace Game.Spells public bool SpellCancelsAuraEffect(AuraEffect aurEff) { - if (!HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + if (!HasAttribute(SpellAttr1.ImmunityPurgesEffect)) return false; if (aurEff.GetSpellInfo().HasAttribute(SpellAttr0.NoImmunities)) @@ -2793,7 +2793,7 @@ namespace Game.Spells SpellPowerCost cost = new(); // Spell drain all exist power on cast (Only paladin lay of Hands) - if (HasAttribute(SpellAttr1.DrainAllPower)) + if (HasAttribute(SpellAttr1.UseAllMana)) { // If power type - health drain all if (power.PowerType == PowerType.Health) @@ -3389,7 +3389,7 @@ namespace Game.Spells } // Special case: effects which determine positivity of whole spell - if (spellInfo.HasAttribute(SpellAttr1.DontRefreshDurationOnRecast)) + if (spellInfo.HasAttribute(SpellAttr1.AuraUnique)) { // check for targets, there seems to be an assortment of dummy triggering spells that should be negative foreach (var otherEffect in spellInfo.GetEffects()) diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index fcfb55634..928288aaf 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -3713,7 +3713,7 @@ namespace Game.Entities // spell should dispel area aura, but doesn't have the attribute // may be db data bug, or blizz may keep reapplying area auras every update with checking immunity // that will be clear if we get more spells with problem like this - spellInfo.AttributesEx |= SpellAttr1.DispelAurasOnImmunity; + spellInfo.AttributesEx |= SpellAttr1.ImmunityPurgesEffect; }); // Blizzard (Thorim) @@ -4104,7 +4104,7 @@ namespace Game.Entities // Awaken Flames ApplySpellFix(new[] { 75888 }, spellInfo => { - spellInfo.AttributesEx |= SpellAttr1.CantTargetSelf; + spellInfo.AttributesEx |= SpellAttr1.ExcludeCaster; }); // ENDOF RUBY SANCTUM SPELLS @@ -4203,7 +4203,7 @@ namespace Game.Entities // Gaze of Occu'thar ApplySpellFix(new[] { 96942 }, spellInfo => { - spellInfo.AttributesEx &= ~SpellAttr1.Channeled1; + spellInfo.AttributesEx &= ~SpellAttr1.IsChannelled; }); // Evolution