diff options
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 48 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 13 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 17 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 35 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 5 |
7 files changed, 75 insertions, 51 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a309f972ac0..f2549dcf621 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7979,10 +7979,6 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT continue; } - // not allow proc extra attack spell at extra attack - if (m_extraAttacks && spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - return; - float chance = (float)spellInfo->ProcChance; if (spellData.SpellPPMRate) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e515a048830..2daf345215c 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -314,7 +314,6 @@ Unit::Unit(bool isWorldObject) : m_modAttackSpeedPct[OFF_ATTACK] = 1.0f; m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f; - m_extraAttacks = 0; m_canDualWield = false; m_movementCounter = 0; @@ -389,6 +388,8 @@ Unit::Unit(bool isWorldObject) : _isWalkingBeforeCharm = false; _instantCast = false; _isCombatDisallowed = false; + + _lastExtraAttackSpell = 0; } //////////////////////////////////////////////////////////// @@ -445,6 +446,21 @@ void Unit::Update(uint32 p_time) m_combatManager.Update(p_time); + _lastDamagedTargetGuid = ObjectGuid::Empty; + if (_lastExtraAttackSpell) + { + while (!extraAttacksTargets.empty()) + { + auto itr = extraAttacksTargets.begin(); + ObjectGuid targetGuid = itr->first; + uint32 count = itr->second; + extraAttacksTargets.erase(itr); + if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid)) + HandleProcExtraAttackFor(victim, count); + } + _lastExtraAttackSpell = 0; + } + // not implemented before 3.0.2 if (uint32 base_att = getAttackTimer(BASE_ATTACK)) setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time)); @@ -2056,7 +2072,10 @@ void Unit::HandleEmoteCommand(Emote emoteId) void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra) { - if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) + if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) + return; + + if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra) return; if (!victim->IsAlive()) @@ -2071,6 +2090,9 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr if (attType != BASE_ATTACK && attType != OFF_ATTACK) return; // ignore ranged case + if (!extra && _lastExtraAttackSpell) + _lastExtraAttackSpell = 0; + if (GetTypeId() == TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED) && !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CANNOT_TURN)) SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells) @@ -2090,6 +2112,8 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr Unit::DealDamageMods(victim, damageInfo.Damages[i].Damage, &damageInfo.Damages[i].Absorb); SendAttackStateUpdate(&damageInfo); + _lastDamagedTargetGuid = victim->GetGUID(); + DealMeleeDamage(&damageInfo, true); DamageInfo dmgInfo(damageInfo); @@ -2104,15 +2128,29 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr } } -void Unit::HandleProcExtraAttackFor(Unit* victim) +void Unit::HandleProcExtraAttackFor(Unit* victim, uint32 count) { - while (m_extraAttacks) + while (count) { + --count; AttackerStateUpdate(victim, BASE_ATTACK, true); - --m_extraAttacks; } } +void Unit::AddExtraAttacks(uint32 count) +{ + ObjectGuid targetGUID = _lastDamagedTargetGuid; + if (!targetGUID) + { + if (ObjectGuid selection = GetTarget()) + targetGUID = selection; // Spell was cast directly (not triggered by aura) + else + return; + } + + extraAttacksTargets[targetGUID] += count; +} + MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const { if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index cffd683d28e..ea63c22ea3a 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -834,7 +834,6 @@ class TC_GAME_API Unit : public WorldObject bool IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const; float GetMeleeRange(Unit const* target) const; virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const = 0; - uint32 m_extraAttacks; bool m_canDualWield; void _addAttacker(Unit* pAttacker); // must be called only from Unit::Attack(Unit*) @@ -991,7 +990,13 @@ class TC_GAME_API Unit : public WorldObject void CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK); void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss); - void HandleProcExtraAttackFor(Unit* victim); + void HandleProcExtraAttackFor(Unit* victim, uint32 count); + + void SetLastExtraAttackSpell(uint32 spellId) { _lastExtraAttackSpell = spellId; } + uint32 GetLastExtraAttackSpell() const { return _lastExtraAttackSpell; } + void AddExtraAttacks(uint32 count); + void SetLastDamagedTargetGuid(ObjectGuid guid) { _lastDamagedTargetGuid = guid; } + ObjectGuid GetLastDamagedTargetGuid() const { return _lastDamagedTargetGuid; } void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false, Spell* spell = nullptr); void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss); @@ -1884,6 +1889,10 @@ class TC_GAME_API Unit : public WorldObject int8 m_comboPoints; std::unordered_set<Unit*> m_ComboPointHolders; + uint32 _lastExtraAttackSpell; + std::unordered_map<ObjectGuid /*guid*/, uint32 /*count*/> extraAttacksTargets; + ObjectGuid _lastDamagedTargetGuid; + bool m_cleanupDone; // lock made to not add stuff after cleanup before delete bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world bool _instantCast; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 9e2275f43e4..a60e6b44645 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -989,8 +989,21 @@ bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventIn // Don't proc extra attacks while already processing extra attack spell uint32 triggerSpellId = GetSpellEffectInfo().TriggerSpell; if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId)) - if (aurApp->GetTarget()->m_extraAttacks && triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - return false; + { + if (triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + { + uint32 lastExtraAttackSpell = eventInfo.GetActor()->GetLastExtraAttackSpell(); + + // Patch 1.12.0(?) extra attack abilities can no longer chain proc themselves + if (lastExtraAttackSpell == triggerSpellId) + return false; + + // Patch 2.2.0 Sword Specialization (Warrior, Rogue) extra attack can no longer proc additional extra attacks + // 3.3.5 Sword Specialization (Warrior), Hack and Slash (Rogue) + if (lastExtraAttackSpell == 16459 || lastExtraAttackSpell == 66923) + return false; + } + } break; } case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 2e7c93c9d80..450957a5ca9 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -215,28 +215,6 @@ void SpellCastTargets::Write(WorldPackets::Spells::SpellTargetData& data) data.Name = m_strTarget; } -ObjectGuid SpellCastTargets::GetOrigUnitTargetGUID() const -{ - switch (m_origObjectTargetGUID.GetHigh()) - { - case HighGuid::Player: - case HighGuid::Vehicle: - case HighGuid::Unit: - case HighGuid::Pet: - return m_origObjectTargetGUID; - default: - return ObjectGuid(); - } -} - -void SpellCastTargets::SetOrigUnitTarget(Unit* target) -{ - if (!target) - return; - - m_origObjectTargetGUID = target->GetGUID(); -} - ObjectGuid SpellCastTargets::GetUnitTargetGUID() const { if (m_objectTargetGUID.IsUnit()) @@ -651,7 +629,7 @@ Spell::~Spell() void Spell::InitExplicitTargets(SpellCastTargets const& targets) { m_targets = targets; - m_targets.SetOrigUnitTarget(m_targets.GetUnitTarget()); + // this function tries to correct spell explicit targets for spell // client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside // this also makes sure that we correctly send explicit targets to client (removes redundant data) @@ -2515,6 +2493,8 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell) } else { + caster->SetLastDamagedTargetGuid(spell->unitTarget->GetGUID()); + // Add bonuses and fill damageInfo struct caster->CalculateSpellDamageTaken(&damageInfo, spell->m_damage, spell->m_spellInfo, spell->m_attackType, IsCrit, spell); Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); @@ -3711,13 +3691,8 @@ void Spell::_handle_finish_phase() unitCaster->AddComboPoints(m_comboTarget, m_comboPointGain); } - if (unitCaster->m_extraAttacks && m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) - { - if (Unit* victim = ObjectAccessor::GetUnit(*unitCaster, m_targets.GetOrigUnitTargetGUID())) - unitCaster->HandleProcExtraAttackFor(victim); - else - unitCaster->m_extraAttacks = 0; - } + if (m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + unitCaster->SetLastExtraAttackSpell(m_spellInfo->Id); } // Handle procs on finish diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 238007a0178..c9f7b38cc69 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -150,9 +150,6 @@ class TC_GAME_API SpellCastTargets void SetTargetFlag(SpellCastTargetFlags flag) { m_targetMask |= flag; } - ObjectGuid GetOrigUnitTargetGUID() const; - void SetOrigUnitTarget(Unit* target); - ObjectGuid GetUnitTargetGUID() const; Unit* GetUnitTarget() const; void SetUnitTarget(Unit* target); @@ -217,7 +214,6 @@ class TC_GAME_API SpellCastTargets Item* m_itemTarget; // object GUID/etc, can be used always - ObjectGuid m_origObjectTargetGUID; ObjectGuid m_objectTargetGUID; ObjectGuid m_itemTargetGUID; uint32 m_itemTargetEntry; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 5712f1f92c1..1a910fc16d1 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4122,10 +4122,7 @@ void Spell::EffectAddExtraAttacks() if (!unitTarget || !unitTarget->IsAlive()) return; - if (unitTarget->m_extraAttacks) - return; - - unitTarget->m_extraAttacks = damage; + unitTarget->AddExtraAttacks(damage); ExecuteLogEffectExtraAttacks(effectInfo->EffectIndex, unitTarget, damage); } |