aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Player/Player.cpp4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp49
-rw-r--r--src/server/game/Entities/Unit/Unit.h13
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp12
-rw-r--r--src/server/game/Spells/Spell.cpp35
-rw-r--r--src/server/game/Spells/SpellDefines.h4
-rw-r--r--src/server/game/Spells/SpellEffects.cpp5
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);
}