From e89a36a2320ea5dce9071be0e1eb7385a496859e Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 6 Jan 2022 00:17:58 -0500 Subject: [PATCH] Core/Spells: SPELL_AURA_48 implementation Port From (https://github.com/TrinityCore/TrinityCore/commit/37178ff311af95c4a2035a38839b5e8a9afe2af5) --- Source/Game/Entities/Unit/Unit.Spells.cs | 219 ++++++++++++----------- Source/Game/Handlers/PetHandler.cs | 27 ++- Source/Game/Handlers/SpellHandler.cs | 7 +- Source/Game/Spells/Auras/AuraEffect.cs | 4 + Source/Game/Spells/SpellInfo.cs | 3 +- Source/Game/Spells/SpellManager.cs | 19 +- 6 files changed, 162 insertions(+), 117 deletions(-) diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 0225806f0..35b75a8b7 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1041,8 +1041,8 @@ namespace Game.Entities return 0; } - public virtual bool HasSpellFocus(Spell focusSpell = null) { return false; } - + public virtual bool HasSpellFocus(Spell focusSpell = null) { return false; } + /// /// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING /// @@ -1075,7 +1075,7 @@ namespace Game.Entities return true; return false; } - + public bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura = 0) { var auras = GetAuraEffectsByType(type); @@ -1428,7 +1428,7 @@ namespace Game.Entities return false; } - + public static void ProcSkillsAndAuras(Unit actor, Unit actionTarget, ProcFlags typeMaskActor, ProcFlags typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo) { WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack; @@ -1627,51 +1627,51 @@ namespace Game.Entities switch (CSpellType) { case CurrentSpellTypes.Generic: + { + // generic spells always break channeled not delayed spells + InterruptSpell(CurrentSpellTypes.Channeled, false); + + // autorepeat breaking + if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null) { - // generic spells always break channeled not delayed spells - InterruptSpell(CurrentSpellTypes.Channeled, false); - - // autorepeat breaking - if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null) - { - // break autorepeat if not Auto Shot - if (m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75) - InterruptSpell(CurrentSpellTypes.AutoRepeat); - m_AutoRepeatFirstCast = true; - } - if (pSpell.m_spellInfo.CalcCastTime() > 0) - AddUnitState(UnitState.Casting); - - break; - } - case CurrentSpellTypes.Channeled: - { - // channel spells always break generic non-delayed and any channeled spells - InterruptSpell(CurrentSpellTypes.Generic, false); - InterruptSpell(CurrentSpellTypes.Channeled); - - // it also does break autorepeat if not Auto Shot - if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null && - m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75) + // break autorepeat if not Auto Shot + if (m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75) InterruptSpell(CurrentSpellTypes.AutoRepeat); + m_AutoRepeatFirstCast = true; + } + if (pSpell.m_spellInfo.CalcCastTime() > 0) AddUnitState(UnitState.Casting); - break; - } - case CurrentSpellTypes.AutoRepeat: - { - // only Auto Shoot does not break anything - if (pSpell.m_spellInfo.Id != 75) - { - // generic autorepeats break generic non-delayed and channeled non-delayed spells - InterruptSpell(CurrentSpellTypes.Generic, false); - InterruptSpell(CurrentSpellTypes.Channeled, false); - } - // special action: set first cast flag - m_AutoRepeatFirstCast = true; + break; + } + case CurrentSpellTypes.Channeled: + { + // channel spells always break generic non-delayed and any channeled spells + InterruptSpell(CurrentSpellTypes.Generic, false); + InterruptSpell(CurrentSpellTypes.Channeled); - break; + // it also does break autorepeat if not Auto Shot + if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null && + m_currentSpells[CurrentSpellTypes.AutoRepeat].m_spellInfo.Id != 75) + InterruptSpell(CurrentSpellTypes.AutoRepeat); + AddUnitState(UnitState.Casting); + + break; + } + case CurrentSpellTypes.AutoRepeat: + { + // only Auto Shoot does not break anything + if (pSpell.m_spellInfo.Id != 75) + { + // generic autorepeats break generic non-delayed and channeled non-delayed spells + InterruptSpell(CurrentSpellTypes.Generic, false); + InterruptSpell(CurrentSpellTypes.Channeled, false); } + // special action: set first cast flag + m_AutoRepeatFirstCast = true; + + break; + } default: break; // other spell types don't break anything now } @@ -1948,74 +1948,74 @@ namespace Game.Entities // Melee and Ranged Spells case SpellDmgClass.Ranged: case SpellDmgClass.Melee: + { + // Physical Damage + if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal)) { - // Physical Damage - if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal)) + // Spells with this attribute were already calculated in MeleeSpellHitResult + if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell)) { - // Spells with this attribute were already calculated in MeleeSpellHitResult - if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell)) - { - // Get blocked status - blocked = IsSpellBlocked(victim, spellInfo, attackType); - } + // Get blocked status + blocked = IsSpellBlocked(victim, spellInfo, attackType); } - - if (crit) - { - damageInfo.HitInfo |= HitInfo.CriticalHit; - - // Calculate crit bonus - uint crit_bonus = (uint)damage; - // Apply crit_damage bonus for melee spells - Player modOwner = GetSpellModOwner(); - if (modOwner != null) - modOwner.ApplySpellMod(spellInfo, SpellModOp.CritDamageAndHealing, ref crit_bonus); - damage += (int)crit_bonus; - - // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS - float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(AuraType.ModCritDamageBonus, (uint)spellInfo.GetSchoolMask()) - 1.0f) * 100; - - if (critPctDamageMod != 0) - MathFunctions.AddPct(ref damage, (int)critPctDamageMod); - } - - // Spell weapon based damage CAN BE crit & blocked at same time - if (blocked) - { - // double blocked amount if block is critical - float value = victim.GetBlockPercent(GetLevel()); - if (victim.IsBlockCritical()) - value *= 2; // double blocked percent - damageInfo.blocked = (uint)MathFunctions.CalculatePct(damage, value); - if (damage <= damageInfo.blocked) - { - damageInfo.blocked = (uint)damage; - damageInfo.fullBlock = true; - } - damage -= (int)damageInfo.blocked; - } - - if (CanApplyResilience()) - ApplyResilience(victim, ref damage); - - break; } + + if (crit) + { + damageInfo.HitInfo |= HitInfo.CriticalHit; + + // Calculate crit bonus + uint crit_bonus = (uint)damage; + // Apply crit_damage bonus for melee spells + Player modOwner = GetSpellModOwner(); + if (modOwner != null) + modOwner.ApplySpellMod(spellInfo, SpellModOp.CritDamageAndHealing, ref crit_bonus); + damage += (int)crit_bonus; + + // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS + float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(AuraType.ModCritDamageBonus, (uint)spellInfo.GetSchoolMask()) - 1.0f) * 100; + + if (critPctDamageMod != 0) + MathFunctions.AddPct(ref damage, (int)critPctDamageMod); + } + + // Spell weapon based damage CAN BE crit & blocked at same time + if (blocked) + { + // double blocked amount if block is critical + float value = victim.GetBlockPercent(GetLevel()); + if (victim.IsBlockCritical()) + value *= 2; // double blocked percent + damageInfo.blocked = (uint)MathFunctions.CalculatePct(damage, value); + if (damage <= damageInfo.blocked) + { + damageInfo.blocked = (uint)damage; + damageInfo.fullBlock = true; + } + damage -= (int)damageInfo.blocked; + } + + if (CanApplyResilience()) + ApplyResilience(victim, ref damage); + + break; + } // Magical Attacks case SpellDmgClass.None: case SpellDmgClass.Magic: + { + // If crit add critical bonus + if (crit) { - // If crit add critical bonus - if (crit) - { - damageInfo.HitInfo |= HitInfo.CriticalHit; - damage = (int)SpellCriticalDamageBonus(this, spellInfo, (uint)damage, victim); - } - - if (CanApplyResilience()) - ApplyResilience(victim, ref damage); - - break; + damageInfo.HitInfo |= HitInfo.CriticalHit; + damage = (int)SpellCriticalDamageBonus(this, spellInfo, (uint)damage, victim); } + + if (CanApplyResilience()) + ApplyResilience(victim, ref damage); + + break; + } default: break; } @@ -2241,7 +2241,7 @@ namespace Game.Entities } public virtual bool IsAffectedByDiminishingReturns() { return (GetCharmerOrOwnerPlayerOrPlayerItself() != null); } - + public DiminishingLevels GetDiminishing(DiminishingGroup group) { DiminishingReturn diminish = m_Diminishing[(int)group]; @@ -2568,7 +2568,7 @@ namespace Game.Entities { int[] bp = new int[SpellConst.MaxEffects]; foreach (var spellEffectInfo in spellEntry.GetEffects()) - bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints; + bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints; bp[i] = seatId; @@ -2611,7 +2611,7 @@ namespace Game.Entities { return GetAuraApplication(predicate) != null; } - + public bool HasAuraEffect(uint spellId, uint effIndex, ObjectGuid casterGUID = default) { var range = m_appliedAuras.LookupByKey(spellId); @@ -2678,6 +2678,15 @@ namespace Game.Entities return false; } + public bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint triggerSpell) + { + foreach (var aura in GetAuraEffectsByType(auratype)) + if (aura.GetSpellEffectInfo().TriggerSpell == triggerSpell) + return true; + + return false; + } + public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags flag, ObjectGuid guid = default) { if (!HasInterruptFlag(flag)) diff --git a/Source/Game/Handlers/PetHandler.cs b/Source/Game/Handlers/PetHandler.cs index 66c802d24..536b63140 100644 --- a/Source/Game/Handlers/PetHandler.cs +++ b/Source/Game/Handlers/PetHandler.cs @@ -677,13 +677,30 @@ namespace Game return; } - // do not cast not learned spells - if (!caster.HasSpell(spellInfo.Id) || spellInfo.IsPassive()) - return; - SpellCastTargets targets = new(caster, petCastSpell.Cast); - Spell spell = new(caster, spellInfo, TriggerCastFlags.None); + TriggerCastFlags triggerCastFlags = TriggerCastFlags.None; + + if (spellInfo.IsPassive()) + return; + + // cast only learned spells + if (!caster.HasSpell(spellInfo.Id)) + { + bool allow = false; + + // allow casting of spells triggered by clientside periodic trigger auras + if (caster.HasAuraTypeWithTriggerSpell(AuraType.PeriodicTriggerSpellFromClient, spellInfo.Id)) + { + allow = true; + triggerCastFlags = TriggerCastFlags.FullMask; + } + + if (!allow) + return; + } + + Spell spell = new(caster, spellInfo, triggerCastFlags); spell.m_fromClient = true; spell.m_misc.Data0 = petCastSpell.Cast.Misc[0]; spell.m_misc.Data1 = petCastSpell.Cast.Misc[1]; diff --git a/Source/Game/Handlers/SpellHandler.cs b/Source/Game/Handlers/SpellHandler.cs index 60db3f009..e7bccd532 100644 --- a/Source/Game/Handlers/SpellHandler.cs +++ b/Source/Game/Handlers/SpellHandler.cs @@ -314,15 +314,12 @@ namespace Game if (go.GetSpellForLock(caster.ToPlayer()) == spellInfo) allow = true; - // TODO: Preparation for #23204 // allow casting of spells triggered by clientside periodic trigger auras - /* - if (caster->HasAuraTypeWithTriggerSpell(SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT, spellId)) + if (caster.HasAuraTypeWithTriggerSpell(AuraType.PeriodicTriggerSpellFromClient, spellInfo.Id)) { allow = true; - triggerFlag = TRIGGERED_FULL_MASK; + triggerFlag = TriggerCastFlags.FullMask; } - */ if (!allow) return; diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 92968f5c8..14b6bb6c9 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -188,6 +188,7 @@ namespace Game.Spells case AuraType.PeriodicHeal: case AuraType.ObsModHealth: case AuraType.PeriodicTriggerSpell: + case AuraType.PeriodicTriggerSpellFromClient: case AuraType.PeriodicEnergize: case AuraType.PeriodicLeech: case AuraType.PeriodicHealthFunnel: @@ -520,6 +521,9 @@ namespace Game.Spells case AuraType.PeriodicTriggerSpell: HandlePeriodicTriggerSpellAuraTick(target, caster); break; + case AuraType.PeriodicTriggerSpellFromClient: + // Don't actually do anything - client will trigger casts of these spells by itself + break; case AuraType.PeriodicTriggerSpellWithValue: HandlePeriodicTriggerSpellWithValueAuraTick(target, caster); break; diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 9d7c0575c..47294cd79 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -2705,7 +2705,7 @@ namespace Game.Spells case AuraType.PeriodicHeal: case AuraType.ObsModHealth: case AuraType.ObsModPower: - case AuraType.Unk48: + case AuraType.PeriodicTriggerSpellFromClient: case AuraType.PowerBurn: case AuraType.PeriodicLeech: case AuraType.PeriodicManaLeech: @@ -3530,6 +3530,7 @@ namespace Game.Spells case AuraType.AddTargetTrigger: return true; case AuraType.PeriodicTriggerSpellWithValue: + case AuraType.PeriodicTriggerSpellFromClient: case AuraType.PeriodicTriggerSpell: if (!_isPositiveTarget(effect)) { diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index e83396a14..f911c8dd5 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -2935,6 +2935,7 @@ namespace Game.Entities switch (spellEffectInfo.ApplyAuraName) { case AuraType.PeriodicTriggerSpell: + case AuraType.PeriodicTriggerSpellFromClient: case AuraType.PeriodicTriggerSpellWithValue: SpellInfo triggerSpell = Global.SpellMgr.GetSpellInfo(spellEffectInfo.TriggerSpell, Difficulty.None); if (triggerSpell != null) @@ -3257,7 +3258,8 @@ namespace Game.Entities 43109, // Throw Torch 58552, // Return to Orgrimmar 58533, // Return to Stormwind - 21855 // Challenge Flag + 21855, // Challenge Flag + 51122 // Fierce Lightning Stike }, spellInfo => { spellInfo.MaxAffectedTargets = 1; @@ -3578,6 +3580,14 @@ namespace Game.Entities spellInfo.RangeEntry = CliDB.SpellRangeStorage.LookupByKey(13); // 50000yd }); + ApplySpellFix(new[] { + 44327, // Trained Rock Falcon/Hawk Hunting + 44408 // Trained Rock Falcon/Hawk Hunting + }, spellInfo => + { + spellInfo.Speed = 0.0f; + }); + // Summon Corpse Scarabs ApplySpellFix(new[] { 28864, 29105 }, spellInfo => { @@ -3917,6 +3927,13 @@ namespace Game.Entities }); }); + // Mutated Transformation (Professor Putricide) + ApplySpellFix(new[] { 70402 }, spellInfo => + { + // Resistance is calculated inside of SpellScript + spellInfo.AttributesEx4 |= SpellAttr4.IgnoreResistances; + }); + // Empowered Flare (Blood Prince Council) ApplySpellFix(new[] { 71708 }, spellInfo => {