diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-05-08 15:54:15 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-05-08 15:54:15 +0200 |
commit | de592386dcd6ac85feb11d2af85538d62c192696 (patch) | |
tree | 07f45b6f56f591408263e8efed672dec74c942d7 /src | |
parent | 538fa8e97ff4b4e36a59e37fd74ea8958e6e30d2 (diff) |
Core/Spells: Autorepeat casting fixes
* Fixed cast bars of ranged spells not disappearing when canceled while autoshooting
* Replaced hacky 500ms delay on non auto shot autorepeat spells with native spell cast time (wands have 500ms cast time)
* Update cooldowns before attempting to cast autorepeat spells (for cases when cooldown ends on the same server tick as cast attempt)
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 30 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 29 | ||||
-rw-r--r-- | src/server/game/Spells/SpellHistory.cpp | 5 |
4 files changed, 33 insertions, 33 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b4a689e6f4a..2b24cc04074 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -299,7 +299,7 @@ SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellIn Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject), m_lastSanctuaryTime(0), LastCharmerGUID(), movespline(new Movement::MoveSpline()), - m_ControlledByPlayer(false), m_AutoRepeatFirstCast(false), m_procDeep(0), m_transformSpell(0), + m_ControlledByPlayer(false), m_procDeep(0), m_transformSpell(0), m_removedAurasCount(0), m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None), m_unitMovedByMe(nullptr), m_playerMovingMe(nullptr), m_charmer(nullptr), m_charmed(nullptr), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr), @@ -2721,6 +2721,8 @@ void Unit::_DeleteRemovedAuras() void Unit::_UpdateSpells(uint32 time) { + _spellHistory->Update(); + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]) _UpdateAutoRepeatSpell(); @@ -2774,8 +2776,6 @@ void Unit::_UpdateSpells(uint32 time) ++itr; } } - - _spellHistory->Update(); } void Unit::_UpdateAutoRepeatSpell() @@ -2789,17 +2789,11 @@ void Unit::_UpdateAutoRepeatSpell() // cancel wand shoot if (autoRepeatSpellInfo->Id != 75) InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - m_AutoRepeatFirstCast = true; return; } - // apply delay (Auto Shot (spellID 75) not affected) - if (m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 && autoRepeatSpellInfo->Id != 75) - setAttackTimer(RANGED_ATTACK, 500); - m_AutoRepeatFirstCast = false; - // castroutine - if (isAttackReady(RANGED_ATTACK)) + if (isAttackReady(RANGED_ATTACK) && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_PREPARING) { // Check if able to cast SpellCastResult result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true); @@ -2814,11 +2808,8 @@ void Unit::_UpdateAutoRepeatSpell() } // we want to shoot - Spell* spell = new Spell(this, autoRepeatSpellInfo, TRIGGERED_FULL_MASK); + Spell* spell = new Spell(this, autoRepeatSpellInfo, TRIGGERED_IGNORE_GCD); spell->prepare(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets); - - // all went good, reset attack - resetAttackTimer(RANGED_ATTACK); } } @@ -2831,14 +2822,13 @@ void Unit::SetCurrentCastSpell(Spell* pSpell) if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self return; - // break same type spell if it is not delayed - InterruptSpell(CSpellType, false); - // special breakage effects: switch (CSpellType) { case CURRENT_GENERIC_SPELL: { + InterruptSpell(CURRENT_GENERIC_SPELL, false); + // generic spells always break channeled not delayed spells if (m_currentSpells[CURRENT_CHANNELED_SPELL] && !m_currentSpells[CURRENT_CHANNELED_SPELL]->GetSpellInfo()->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL)) InterruptSpell(CURRENT_CHANNELED_SPELL, false); @@ -2849,7 +2839,6 @@ void Unit::SetCurrentCastSpell(Spell* pSpell) // break autorepeat if not Auto Shot if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75) InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - m_AutoRepeatFirstCast = true; } if (pSpell->GetCastTime() > 0) AddUnitState(UNIT_STATE_CASTING); @@ -2872,6 +2861,9 @@ void Unit::SetCurrentCastSpell(Spell* pSpell) } case CURRENT_AUTOREPEAT_SPELL: { + if (m_currentSpells[CSpellType] && m_currentSpells[CSpellType]->getState() == SPELL_STATE_IDLE) + m_currentSpells[CSpellType]->setState(SPELL_STATE_FINISHED); + // only Auto Shoot does not break anything if (pSpell->GetSpellInfo()->Id != 75) { @@ -2879,8 +2871,6 @@ void Unit::SetCurrentCastSpell(Spell* pSpell) InterruptSpell(CURRENT_GENERIC_SPELL, false); InterruptSpell(CURRENT_CHANNELED_SPELL, false); } - // special action: set first cast flag - m_AutoRepeatFirstCast = true; break; } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 273ce6cd4be..7774814405b 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1919,8 +1919,6 @@ class TC_GAME_API Unit : public WorldObject bool m_ControlledByPlayer; - bool m_AutoRepeatFirstCast; - float m_createStats[MAX_STATS]; float m_floatStatPosBuff[MAX_STATS]; float m_floatStatNegBuff[MAX_STATS]; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index e207befbf55..1283068269b 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3338,7 +3338,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks if (_triggeredCastFlags & TRIGGERED_IGNORE_TARGET_CHECK && result == SPELL_FAILED_BAD_TARGETS) result = SPELL_CAST_OK; - if (result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering + if (result != SPELL_CAST_OK) { // 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 @@ -3355,6 +3355,10 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const else SendCastResult(result); + // queue autorepeat spells for future repeating + if (GetCurrentContainer() == CURRENT_AUTOREPEAT_SPELL && m_caster->IsUnit()) + m_caster->ToUnit()->SetCurrentCastSpell(this); + finish(false); return result; } @@ -4084,6 +4088,9 @@ void Spell::SendSpellCooldown() 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(RANGED_ATTACK); } void Spell::update(uint32 difftime) @@ -4126,7 +4133,7 @@ void Spell::update(uint32 difftime) m_timer -= 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); break; @@ -4186,6 +4193,10 @@ void Spell::finish(bool ok) if (!unitCaster) 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(CURRENT_AUTOREPEAT_SPELL) == this) + m_spellState = SPELL_STATE_IDLE; + if (m_spellInfo->IsChanneled()) unitCaster->UpdateInterruptMask(); @@ -5464,12 +5475,18 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32 return SPELL_FAILED_NOT_READY; } - if (!IsIgnoringCooldowns() && m_caster->ToUnit() && !m_caster->ToUnit()->GetSpellHistory()->IsReady(m_spellInfo, m_castItemEntry)) + if (!IsIgnoringCooldowns() && m_caster->ToUnit()) { - if (m_triggeredByAuraSpell) + if (!m_caster->ToUnit()->GetSpellHistory()->IsReady(m_spellInfo, m_castItemEntry)) + { + if (m_triggeredByAuraSpell) + return SPELL_FAILED_DONT_REPORT; + else + return SPELL_FAILED_NOT_READY; + } + + if ((IsAutoRepeat() || m_spellInfo->CategoryId == 76) && !m_caster->ToUnit()->isAttackReady(RANGED_ATTACK)) return SPELL_FAILED_DONT_REPORT; - else - return SPELL_FAILED_NOT_READY; } } diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp index fffa4139ec8..c97b36d0a3a 100644 --- a/src/server/game/Spells/SpellHistory.cpp +++ b/src/server/game/Spells/SpellHistory.cpp @@ -430,11 +430,6 @@ void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spel { if (!forcedCooldown) { - // shoot spells used equipped item cooldown values already assigned in SetBaseAttackTime(RANGED_ATTACK) - // prevent 0 cooldowns set by another way - if (cooldown <= Duration::zero() && categoryCooldown <= Duration::zero() && (categoryId == 76 || (spellInfo->IsAutoRepeatRangedSpell() && spellInfo->Id != 75))) - cooldown = Milliseconds(*_owner->m_unitData->RangedAttackRoundBaseTime); - // Now we have cooldown data (if found any), time to apply mods if (Player* modOwner = _owner->GetSpellModOwner()) { |