From 95d134b512bdd1753f1d8200f8ee2789d24b3442 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Wed, 1 Jun 2022 16:28:01 -0400 Subject: [PATCH] Core/Spells: Autorepeat casting fixes Port From (https://github.com/TrinityCore/TrinityCore/commit/de592386dcd6ac85feb11d2af85538d62c192696) --- Source/Game/Entities/Unit/Unit.Fields.cs | 1 - Source/Game/Entities/Unit/Unit.Spells.cs | 12 ++++------ Source/Game/Entities/Unit/Unit.cs | 17 ++++---------- Source/Game/Spells/Spell.cs | 29 +++++++++++++++++++----- Source/Game/Spells/SpellHistory.cs | 5 ---- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Source/Game/Entities/Unit/Unit.Fields.cs b/Source/Game/Entities/Unit/Unit.Fields.cs index 334626771..4fb23a92a 100644 --- a/Source/Game/Entities/Unit/Unit.Fields.cs +++ b/Source/Game/Entities/Unit/Unit.Fields.cs @@ -92,7 +92,6 @@ namespace Game.Entities SpellAuraInterruptFlags m_interruptMask; SpellAuraInterruptFlags2 m_interruptMask2; protected int m_procDeep; - bool m_AutoRepeatFirstCast; SpellHistory _spellHistory; //Auras diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index c09225f5c..35d55a20e 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1627,14 +1627,13 @@ namespace Game.Entities if (pSpell == GetCurrentSpell(CSpellType)) // avoid breaking self return; - // break same type spell if it is not delayed - InterruptSpell(CSpellType, false); - // special breakage effects: switch (CSpellType) { case CurrentSpellTypes.Generic: { + InterruptSpell(CurrentSpellTypes.Generic, false); + // generic spells always break channeled not delayed spells if (GetCurrentSpell(CurrentSpellTypes.Channeled) != null && !GetCurrentSpell(CurrentSpellTypes.Channeled).GetSpellInfo().HasAttribute(SpellAttr5.AllowActionsDuringChannel)) InterruptSpell(CurrentSpellTypes.Channeled, false); @@ -1645,7 +1644,6 @@ namespace Game.Entities // 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); @@ -1668,6 +1666,9 @@ namespace Game.Entities } case CurrentSpellTypes.AutoRepeat: { + if (GetCurrentSpell(CSpellType) && GetCurrentSpell(CSpellType).GetState() == SpellState.Idle) + GetCurrentSpell(CSpellType).SetState(SpellState.Finished); + // only Auto Shoot does not break anything if (pSpell.m_spellInfo.Id != 75) { @@ -1675,9 +1676,6 @@ namespace Game.Entities InterruptSpell(CurrentSpellTypes.Generic, false); InterruptSpell(CurrentSpellTypes.Channeled, false); } - // special action: set first cast flag - m_AutoRepeatFirstCast = true; - break; } default: diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 0eb592ddb..fa7a4617f 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -215,6 +215,8 @@ namespace Game.Entities void _UpdateSpells(uint diff) { + _spellHistory.Update(); + if (GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null) _UpdateAutoRepeatSpell(); @@ -264,8 +266,6 @@ namespace Game.Entities } } } - - _spellHistory.Update(); } public void HandleEmoteCommand(Emote emoteId, Player target = null, uint[] spellVisualKitIds = null, int sequenceVariation = 0) @@ -1568,17 +1568,11 @@ namespace Game.Entities // cancel wand shoot if (autoRepeatSpellInfo.Id != 75) InterruptSpell(CurrentSpellTypes.AutoRepeat); - m_AutoRepeatFirstCast = true; return; } - // apply delay (Auto Shot (spellID 75) not affected) - if (m_AutoRepeatFirstCast && GetAttackTimer(WeaponAttackType.RangedAttack) < 500 && autoRepeatSpellInfo.Id != 75) - SetAttackTimer(WeaponAttackType.RangedAttack, 500); - m_AutoRepeatFirstCast = false; - // castroutine - if (IsAttackReady(WeaponAttackType.RangedAttack)) + if (IsAttackReady(WeaponAttackType.RangedAttack) && GetCurrentSpell(CurrentSpellTypes.AutoRepeat).GetState() != SpellState.Preparing) { // Check if able to cast SpellCastResult result = m_currentSpells[CurrentSpellTypes.AutoRepeat].CheckCast(true); @@ -1593,11 +1587,8 @@ namespace Game.Entities } // we want to shoot - Spell spell = new(this, autoRepeatSpellInfo, TriggerCastFlags.FullMask); + Spell spell = new(this, autoRepeatSpellInfo, TriggerCastFlags.IgnoreGCD); spell.Prepare(m_currentSpells[CurrentSpellTypes.AutoRepeat].m_targets); - - // all went good, reset attack - ResetAttackTimer(WeaponAttackType.RangedAttack); } } diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 4978e7859..bb29fb8f6 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2474,7 +2474,7 @@ namespace Game.Spells // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks if (Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreTargetCheck) && result == SpellCastResult.BadTargets) result = SpellCastResult.SpellCastOk; - if (result != SpellCastResult.SpellCastOk && !IsAutoRepeat()) //always cast autorepeat dummy for triggering + if (result != SpellCastResult.SpellCastOk) { // Periodic auras should be interrupted when aura triggers a spell which can't be cast // for example bladestorm aura should be removed on disarm as of patch 3.3.5 @@ -2491,6 +2491,10 @@ namespace Game.Spells else SendCastResult(result); + // queue autorepeat spells for future repeating + if (GetCurrentContainer() == CurrentSpellTypes.AutoRepeat && m_caster.IsUnit()) + m_caster.ToUnit().SetCurrentCastSpell(this); + Finish(false); return result; } @@ -3259,6 +3263,9 @@ namespace Game.Spells m_caster.ToUnit().GetSpellHistory().HandleCooldowns(m_spellInfo, m_CastItem, this); else m_caster.ToUnit().GetSpellHistory().HandleCooldowns(m_spellInfo, m_castItemEntry, this); + + if (IsAutoRepeat()) + m_caster.ToUnit().ResetAttackTimer(WeaponAttackType.RangedAttack); } public void Update(uint difftime) @@ -3300,7 +3307,7 @@ namespace Game.Spells m_timer -= (int)difftime; } - if (m_timer == 0 && !m_spellInfo.IsNextMeleeSwingSpell() && !IsAutoRepeat()) + if (m_timer == 0 && !m_spellInfo.IsNextMeleeSwingSpell()) // don't CheckCast for instant spells - done in spell.prepare, skip duplicate checks, needed for range checks for example Cast(m_casttime == 0); break; @@ -3365,6 +3372,10 @@ namespace Game.Spells if (unitCaster != null) return; + // successful cast of the initial autorepeat spell is moved to idle state so that it is not deleted as long as autorepeat is active + if (IsAutoRepeat() && unitCaster.GetCurrentSpell(CurrentSpellTypes.AutoRepeat) == this) + m_spellState = SpellState.Idle; + if (m_spellInfo.IsChanneled()) unitCaster.UpdateInterruptMask(); @@ -4651,12 +4662,18 @@ namespace Game.Spells return SpellCastResult.NotReady; } - if (!IsIgnoringCooldowns() && m_caster.ToUnit() != null && !m_caster.ToUnit().GetSpellHistory().IsReady(m_spellInfo, m_castItemEntry)) + if (!IsIgnoringCooldowns() && m_caster.ToUnit() != null) { - if (m_triggeredByAuraSpell != null) + if (!m_caster.ToUnit().GetSpellHistory().IsReady(m_spellInfo, m_castItemEntry)) + { + if (m_triggeredByAuraSpell != null) + return SpellCastResult.DontReport; + else + return SpellCastResult.NotReady; + } + + if ((IsAutoRepeat() || m_spellInfo.CategoryId == 76) && !m_caster.ToUnit().IsAttackReady(WeaponAttackType.RangedAttack)) return SpellCastResult.DontReport; - else - return SpellCastResult.NotReady; } } diff --git a/Source/Game/Spells/SpellHistory.cs b/Source/Game/Spells/SpellHistory.cs index 686aefe95..3ba9d7bc8 100644 --- a/Source/Game/Spells/SpellHistory.cs +++ b/Source/Game/Spells/SpellHistory.cs @@ -365,11 +365,6 @@ namespace Game.Spells { if (!forcedCooldown.HasValue) { - // shoot spells used equipped item cooldown values already assigned in SetBaseAttackTime(RANGED_ATTACK) - // prevent 0 cooldowns set by another way - if (cooldown <= TimeSpan.Zero && categoryCooldown <= TimeSpan.Zero && (categoryId == 76 || (spellInfo.IsAutoRepeatRangedSpell() && spellInfo.Id != 75))) - cooldown = TimeSpan.FromMilliseconds(_owner.m_unitData.RangedAttackRoundBaseTime); - // Now we have cooldown data (if found any), time to apply mods Player modOwner = _owner.GetSpellModOwner(); if (modOwner)