diff options
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 49 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 13 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 12 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 35 | ||||
-rw-r--r-- | src/server/game/Spells/SpellDefines.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 5 |
7 files changed, 71 insertions, 51 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d0feaf94fa1..f3f4260f7f1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8346,10 +8346,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 (proto->SpellPPMRate) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index c8b29688db7..620b2ec0aba 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -318,7 +318,6 @@ Unit::Unit(bool isWorldObject) : m_attackTimer[i] = 0; } - m_extraAttacks = 0; m_canDualWield = false; m_movementCounter = 0; @@ -398,6 +397,8 @@ Unit::Unit(bool isWorldObject) : _isWalkingBeforeCharm = false; _instantCast = false; _isCombatDisallowed = false; + + _lastExtraAttackSpell = 0; } //////////////////////////////////////////////////////////// @@ -453,6 +454,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)); @@ -2001,7 +2017,10 @@ void Unit::HandleEmoteCommand(Emote emoteId, Player* target /*=nullptr*/, Trinit void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra) { - if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) || HasUnitFlag(UNIT_FLAG_PACIFIED)) + if (HasUnitFlag(UNIT_FLAG_PACIFIED)) + return; + + if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra) return; if (HasAuraType(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES)) @@ -2019,6 +2038,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 && !HasUnitFlag(UNIT_FLAG_POSSESSED) && !HasUnitFlag2(UNIT_FLAG2_CANNOT_TURN)) SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells) @@ -2062,6 +2084,8 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr Unit::DealDamageMods(damageInfo.Attacker, victim, damageInfo.Damage, &damageInfo.Absorb); SendAttackStateUpdate(&damageInfo); + _lastDamagedTargetGuid = victim->GetGUID(); + DealMeleeDamage(&damageInfo, true); DamageInfo dmgInfo(damageInfo); @@ -2083,15 +2107,30 @@ 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) + { + ObjectGuid selection = GetTarget(); + if (!selection.IsEmpty()) + 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()->IsEvadingAttacks()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index bb4a995240f..a253b8f81c6 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -817,7 +817,6 @@ class TC_GAME_API Unit : public WorldObject float GetMeleeRange(Unit const* target) const; virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK) const = 0; bool IsWithinBoundaryRadius(const Unit* obj) const; - uint32 m_extraAttacks; bool m_canDualWield; void _addAttacker(Unit* pAttacker); // must be called only from Unit::Attack(Unit*) @@ -1046,7 +1045,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 const* damageInfo, bool durabilityLoss); @@ -2028,6 +2033,10 @@ class TC_GAME_API Unit : public WorldObject std::unordered_set<AbstractFollower*> m_followingMe; + 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 86b6b42f455..3e747c72915 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1192,8 +1192,16 @@ 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, GetBase()->GetCastDifficulty())) - 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; + } + } 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 6adbfa28086..53656861b92 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -199,28 +199,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::Creature: - 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()) @@ -646,7 +624,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) @@ -2696,6 +2674,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.attacker, damageInfo.target, damageInfo.damage, &damageInfo.absorb); @@ -3955,13 +3935,8 @@ void Spell::_handle_finish_phase() if (m_comboPointGain) unitCaster->AddComboPoints(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/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index 6703e28a61a..56b40fcb439 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -332,9 +332,6 @@ public: void SetTargetFlag(SpellCastTargetFlags flag) { m_targetMask |= flag; } - ObjectGuid GetOrigUnitTargetGUID() const; - void SetOrigUnitTarget(Unit* target); - ObjectGuid GetUnitTargetGUID() const; Unit* GetUnitTarget() const; void SetUnitTarget(Unit* target); @@ -400,7 +397,6 @@ private: 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 44a08afa328..21ea77c8122 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3724,10 +3724,7 @@ void Spell::EffectAddExtraAttacks() if (!unitTarget || !unitTarget->IsAlive()) return; - if (unitTarget->m_extraAttacks) - return; - - unitTarget->m_extraAttacks = damage; + unitTarget->AddExtraAttacks(damage); ExecuteLogEffectExtraAttacks(SpellEffectName(effectInfo->Effect), unitTarget, damage); } |